From 311d9f8af8b29e30859ea1ca97b4e812ccbd3674 Mon Sep 17 00:00:00 2001 From: BHoMBot Date: Mon, 6 Jul 2026 11:30:17 +0100 Subject: [PATCH 01/14] Update assembly file version to 9.3.0.0 --- Units_Engine/Units_Engine.csproj | 2 +- Units_oM/Units_oM.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Units_Engine/Units_Engine.csproj b/Units_Engine/Units_Engine.csproj index 69ca9b9..31849f1 100644 --- a/Units_Engine/Units_Engine.csproj +++ b/Units_Engine/Units_Engine.csproj @@ -8,7 +8,7 @@ BHoM Copyright © https://github.com/BHoM BH.Engine.Units - 9.2.0.0 + 9.3.0.0 true diff --git a/Units_oM/Units_oM.csproj b/Units_oM/Units_oM.csproj index 0efdf88..aac756a 100644 --- a/Units_oM/Units_oM.csproj +++ b/Units_oM/Units_oM.csproj @@ -8,7 +8,7 @@ BHoM Copyright © https://github.com/BHoM BH.oM.Units - 9.2.0.0 + 9.3.0.0 From dfeaeeca1a2b5d95e174475b30532d234566ce19 Mon Sep 17 00:00:00 2001 From: Seun Akanni Date: Sun, 23 Aug 2026 21:22:23 +0100 Subject: [PATCH 02/14] ci: onboard new CI checks (beta tier) --- .github/workflows/ci-beta.yml | 138 ++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 .github/workflows/ci-beta.yml diff --git a/.github/workflows/ci-beta.yml b/.github/workflows/ci-beta.yml new file mode 100644 index 0000000..b7ade02 --- /dev/null +++ b/.github/workflows/ci-beta.yml @@ -0,0 +1,138 @@ +# Beta-tier proxy, BHoM variant. Bundles the tier's checks plus +# copyright-compliance (BHoM enforces OSS copyright; the BHE variant omits it). +# Copy to .github/workflows/ci-beta.yml in each BHoM beta repo. +# Runs on pull_request, non-blocking until a ruleset requires its checks. +# Workflow name CI keeps check contexts bare: required contexts are the job names. + +name: CI + +on: + pull_request: + branches: + - develop + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +jobs: + ci-build: + runs-on: windows-2025-vs2026 + timeout-minutes: 30 + steps: + - name: Run build + uses: BHoM/CI_Toolkit/.github/actions/ci-build@develop + with: + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-code-compliance: + runs-on: windows-2025-vs2026 + timeout-minutes: 20 + permissions: + contents: read + pull-requests: read + actions: write + steps: + - name: Run code compliance + uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop + with: + check_type: code + patterns: '*.cs' + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-copyright-compliance: + runs-on: windows-2025-vs2026 + timeout-minutes: 20 + permissions: + contents: read + pull-requests: read + actions: write + steps: + - name: Run copyright compliance + uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop + with: + check_type: copyright + patterns: '*.cs' + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-dataset-compliance: + runs-on: windows-2025-vs2026 + timeout-minutes: 20 + permissions: + contents: read + pull-requests: read + actions: write + steps: + - name: Run dataset compliance + uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop + with: + check_type: dataset + patterns: ':(icase)*datasets*.json' + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-documentation-compliance: + runs-on: windows-2025-vs2026 + timeout-minutes: 20 + permissions: + contents: read + pull-requests: read + actions: write + steps: + - name: Run documentation compliance + uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop + with: + check_type: documentation + patterns: '*.cs' + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-project-compliance: + runs-on: windows-2025-vs2026 + timeout-minutes: 20 + permissions: + contents: read + pull-requests: read + actions: write + steps: + - name: Run project compliance + uses: BHoM/CI_Toolkit/.github/actions/ci-compliance@develop + with: + check_type: project + patterns: '*AssemblyInfo.cs *.csproj' + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-dataset-tests: + runs-on: windows-2025-vs2026 + timeout-minutes: 30 + steps: + - name: Run dataset tests + uses: BHoM/CI_Toolkit/.github/actions/ci-dataset-tests@develop + with: + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + + ci-serialisation: + runs-on: windows-2025-vs2026 + timeout-minutes: 90 + steps: + - name: Run serialisation + uses: BHoM/CI_Toolkit/.github/actions/ci-serialisation@develop + with: + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} + base_ref: ${{ github.base_ref }} + + ci-versioning: + runs-on: windows-2025-vs2026 + timeout-minutes: 90 + steps: + - name: Run versioning + uses: BHoM/CI_Toolkit/.github/actions/ci-versioning@develop + with: + app_id: ${{ secrets.BHOM_APP_ID }} + private_key: ${{ secrets.BHOM_APP_PRIVATE_KEY }} From 013caf0eedc804cbcc318902e5df902495517810 Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Fri, 28 Aug 2026 19:11:28 +0100 Subject: [PATCH 03/14] Add new QuantityFamilies and To/From SI --- Units_Engine/Convert/FromUnit.cs | 71 +++++++++++++++ Units_Engine/Convert/ToUnit.cs | 69 ++++++++++++++ Units_Engine/Query/ResolveUnit.cs | 145 ++++++++++++++++++++++++++++++ Units_oM/Enums/QuantityFamily.cs | 49 ++++++++++ Units_oM/UnitSpec.cs | 33 +++++++ 5 files changed, 367 insertions(+) create mode 100644 Units_Engine/Convert/FromUnit.cs create mode 100644 Units_Engine/Convert/ToUnit.cs create mode 100644 Units_Engine/Query/ResolveUnit.cs create mode 100644 Units_oM/Enums/QuantityFamily.cs create mode 100644 Units_oM/UnitSpec.cs diff --git a/Units_Engine/Convert/FromUnit.cs b/Units_Engine/Convert/FromUnit.cs new file mode 100644 index 0000000..12d4082 --- /dev/null +++ b/Units_Engine/Convert/FromUnit.cs @@ -0,0 +1,71 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Units; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Converts a value from the given unit symbol to SI, e.g. 12 \"mm\" → 0.012 m.")] + [Input("value", "The value in the specified unit.")] + [Input("unitSymbol", "Unit symbol (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] + [Output("siValue", "The value in SI units, or NaN if the unit is unrecognised.")] + public static double FromUnit(this double value, string unitSymbol) + { + UnitSpec spec = Query.ResolveUnit(unitSymbol); + if (spec == null) + return double.NaN; + + return FromUnit(value, spec); + } + + private static double FromUnit(double value, UnitSpec spec) + { + switch (spec.Family) + { + case QuantityFamily.Length: return value.FromLength(spec.Unit); + case QuantityFamily.Area: return value.FromArea(spec.Unit); + case QuantityFamily.Volume: return value.FromVolume(spec.Unit); + case QuantityFamily.AreaMomentOfInertia: return value.FromAreaMomentOfInertia(spec.Unit); + case QuantityFamily.Pressure: return value.FromPressure(spec.Unit); + case QuantityFamily.Force: return value.FromForce(spec.Unit); + case QuantityFamily.Torque: return value.FromTorque(spec.Unit); + case QuantityFamily.ForcePerLength: return value.FromForcePerLength(spec.Unit); + case QuantityFamily.Angle: return value.FromAngle(spec.Unit); + case QuantityFamily.Mass: return value.FromMass(spec.Unit); + case QuantityFamily.Acceleration: return value.FromAcceleration(spec.Unit); + case QuantityFamily.Density: return value.FromDensity(spec.Unit); + case QuantityFamily.Energy: return value.FromEnergy(spec.Unit); + case QuantityFamily.Speed: return value.FromSpeed(spec.Unit); + case QuantityFamily.Temperature: return value.FromTemperature(spec.Unit); + case QuantityFamily.Time: return value.FromDuration(spec.Unit); + case QuantityFamily.None: return value; + default: return double.NaN; + } + } + } +} diff --git a/Units_Engine/Convert/ToUnit.cs b/Units_Engine/Convert/ToUnit.cs new file mode 100644 index 0000000..21485d6 --- /dev/null +++ b/Units_Engine/Convert/ToUnit.cs @@ -0,0 +1,69 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Units; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Converts an SI value to the given unit symbol, e.g. 0.012 m → 12 \"mm\".")] + [Input("siValue", "The value in SI units.")] + [Input("unitSymbol", "Unit symbol to convert to (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] + [Output("value", "The value in the specified unit, or NaN if the unit is unrecognised.")] + public static double ToUnit(this double siValue, string unitSymbol) + { + UnitSpec spec = Query.ResolveUnit(unitSymbol); + if (spec == null) + return double.NaN; + + return ToUnit(siValue, spec); + } + + private static double ToUnit(double siValue, UnitSpec spec) + { + switch (spec.Family) + { + case QuantityFamily.Length: return siValue.ToLength(spec.Unit); + case QuantityFamily.Area: return siValue.ToArea(spec.Unit); + case QuantityFamily.Volume: return siValue.ToVolume(spec.Unit); + case QuantityFamily.AreaMomentOfInertia: return siValue.ToAreaMomentOfInertia(spec.Unit); + case QuantityFamily.Pressure: return siValue.ToPressure(spec.Unit); + case QuantityFamily.Force: return siValue.ToForce(spec.Unit); + case QuantityFamily.Torque: return siValue.ToTorque(spec.Unit); + case QuantityFamily.ForcePerLength: return siValue.ToForcePerLength(spec.Unit); + case QuantityFamily.Angle: return siValue.ToAngle(spec.Unit); + case QuantityFamily.Mass: return siValue.ToMass(spec.Unit); + case QuantityFamily.Acceleration: return siValue.ToAcceleration(spec.Unit); + case QuantityFamily.Density: return siValue.ToDensity(spec.Unit); + case QuantityFamily.Energy: return siValue.ToEnergy(spec.Unit); + case QuantityFamily.Speed: return siValue.ToSpeed(spec.Unit); + case QuantityFamily.Temperature: return siValue.ToTemperature(spec.Unit); + case QuantityFamily.Time: return siValue.ToDuration(spec.Unit); + case QuantityFamily.None: return siValue; + default: return double.NaN; + } + } + } +} \ No newline at end of file diff --git a/Units_Engine/Query/ResolveUnit.cs b/Units_Engine/Query/ResolveUnit.cs new file mode 100644 index 0000000..e8053fe --- /dev/null +++ b/Units_Engine/Query/ResolveUnit.cs @@ -0,0 +1,145 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Globalization; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UNU = UnitsNet.Units; + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Units; +using BH.Engine.Base; + +namespace BH.Engine.Units +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Resolves a unit symbol string to its corresponding UnitSpec, identifying the quantity family and unit.")] + [Input("unitSymbol", "Unit symbol to resolve (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] + [Output("unitSpec", "The resolved UnitSpec, or null if the unit is unrecognised.")] + public static UnitSpec ResolveUnit(string unitSymbol) + { + string key = unitSymbol?.Trim() ?? ""; + if (key == "" || key == "-") + return new UnitSpec { Family = QuantityFamily.None, Unit = null }; + + if (m_UnitTable.TryGetValue(key, out UnitSpec spec)) + return spec; + + Compute.RecordError($"Unit '{unitSymbol}' is not recognised. Unit symbols are case-sensitive."); + return null; + } + + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + private static Dictionary BuildUnitTable() + { + var table = new Dictionary(StringComparer.Ordinal); + + foreach (var family in m_Families) + { + foreach (object unit in Enum.GetValues(family.Key)) + { + foreach (string symbol in GetAbbreviations(family.Key, (int)(object)unit)) + { + TryAdd(table, symbol, family.Value, unit); + TryAdd(table, Ascii(symbol), family.Value, unit); + } + } + } + + // Torque aliases UnitsNet doesn't publish + TryAdd(table, "Nm", QuantityFamily.Torque, UNU.TorqueUnit.NewtonMeter); + TryAdd(table, "N.m", QuantityFamily.Torque, UNU.TorqueUnit.NewtonMeter); + TryAdd(table, "kNm", QuantityFamily.Torque, UNU.TorqueUnit.KilonewtonMeter); + TryAdd(table, "kN.m", QuantityFamily.Torque, UNU.TorqueUnit.KilonewtonMeter); + + return table; + } + + /***************************************************/ + + private static IEnumerable GetAbbreviations(Type unitType, int unitValue) + { + try + { + return UN.UnitsNetSetup.Default.UnitAbbreviations + .GetUnitAbbreviations(unitType, unitValue, CultureInfo.InvariantCulture); + } + catch + { + return Array.Empty(); + } + } + + /***************************************************/ + + private static void TryAdd(Dictionary table, string symbol, + QuantityFamily family, object unit) + { + if (!string.IsNullOrWhiteSpace(symbol) && !table.ContainsKey(symbol)) + table[symbol] = new UnitSpec { Family = family, Unit = unit }; + } + + /***************************************************/ + + private static string Ascii(string symbol) + { + return symbol? + .Replace("²", "2") + .Replace("³", "3") + .Replace("⁴", "4") + .Replace("⁶", "6"); + } + + /***************************************************/ + /**** Private Fields ****/ + /***************************************************/ + + private static readonly Dictionary m_Families = new Dictionary + { + { typeof(UNU.LengthUnit), QuantityFamily.Length }, + { typeof(UNU.AreaUnit), QuantityFamily.Area }, + { typeof(UNU.VolumeUnit), QuantityFamily.Volume }, + { typeof(UNU.AreaMomentOfInertiaUnit), QuantityFamily.AreaMomentOfInertia }, + { typeof(UNU.PressureUnit), QuantityFamily.Pressure }, + { typeof(UNU.ForceUnit), QuantityFamily.Force }, + { typeof(UNU.TorqueUnit), QuantityFamily.Torque }, + { typeof(UNU.ForcePerLengthUnit), QuantityFamily.ForcePerLength }, + { typeof(UNU.AngleUnit), QuantityFamily.Angle }, + { typeof(UNU.MassUnit), QuantityFamily.Mass }, + }; + + private static readonly Dictionary m_UnitTable = BuildUnitTable(); + + /***************************************************/ + } +} \ No newline at end of file diff --git a/Units_oM/Enums/QuantityFamily.cs b/Units_oM/Enums/QuantityFamily.cs new file mode 100644 index 0000000..cff33ab --- /dev/null +++ b/Units_oM/Enums/QuantityFamily.cs @@ -0,0 +1,49 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System.ComponentModel; + +namespace BH.oM.Units +{ + [Description("Categorises physical quantities for dispatch to the correct conversion method.")] + public enum QuantityFamily + { + None = 0, + Length = 1, + Area = 2, + Volume = 3, + AreaMomentOfInertia = 4, + Pressure = 5, + Force = 6, + Torque = 7, + ForcePerLength = 8, + Angle = 9, + Mass = 10, + Acceleration = 11, + Density = 12, + Energy = 13, + Power = 14, + Speed = 15, + Temperature = 16, + Time = 17, + } +} diff --git a/Units_oM/UnitSpec.cs b/Units_oM/UnitSpec.cs new file mode 100644 index 0000000..af4c25e --- /dev/null +++ b/Units_oM/UnitSpec.cs @@ -0,0 +1,33 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System.ComponentModel; + +namespace BH.oM.Units +{ + [Description("Specification linking a unit symbol to its quantity family and unit enumeration value.")] + public class UnitSpec + { + public virtual QuantityFamily Family { get; set; } = QuantityFamily.None; + public virtual object Unit { get; set; } = null; + } +} \ No newline at end of file From a7689074f19aa1e088353684a911b217f25caef1 Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Tue, 1 Sep 2026 12:13:45 +0100 Subject: [PATCH 04/14] Remove QuantityFamily.cs --- Units_Engine/Convert/FromUnit.cs | 54 ++++++++------ Units_Engine/Convert/ToUnit.cs | 38 +++------- Units_Engine/Query/ResolveUnit.cs | 112 ++++++++++++++++++++++-------- Units_oM/Enums/QuantityFamily.cs | 49 ------------- Units_oM/UnitSpec.cs | 15 ++-- 5 files changed, 137 insertions(+), 131 deletions(-) delete mode 100644 Units_oM/Enums/QuantityFamily.cs diff --git a/Units_Engine/Convert/FromUnit.cs b/Units_Engine/Convert/FromUnit.cs index 12d4082..e769d63 100644 --- a/Units_Engine/Convert/FromUnit.cs +++ b/Units_Engine/Convert/FromUnit.cs @@ -21,18 +21,25 @@ */ using System; -using System.Collections.Generic; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes + using System.ComponentModel; using BH.oM.Base.Attributes; using BH.oM.Units; +using BH.Engine.Base; namespace BH.Engine.Units { public static partial class Convert { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + [Description("Converts a value from the given unit symbol to SI, e.g. 12 \"mm\" → 0.012 m.")] [Input("value", "The value in the specified unit.")] - [Input("unitSymbol", "Unit symbol (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] + [Input("unitSymbol", "Unit symbol (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive. An empty symbol or \"-\" leaves the value unchanged.")] [Output("siValue", "The value in SI units, or NaN if the unit is unrecognised.")] public static double FromUnit(this double value, string unitSymbol) { @@ -40,32 +47,33 @@ public static double FromUnit(this double value, string unitSymbol) if (spec == null) return double.NaN; - return FromUnit(value, spec); + if (spec.Unit == null) + return value; + + return ConvertUnit(value, spec.Unit, spec.SIUnit, unitSymbol); } - private static double FromUnit(double value, UnitSpec spec) + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + // Shared conversion step for FromUnit and ToUnit. The unit and its SI counterpart both come from the + // same UnitSpec, so the only difference between the two is which way round they are passed. + private static double ConvertUnit(double value, Enum fromUnit, Enum toUnit, string unitSymbol) { - switch (spec.Family) + if (double.IsNaN(value) || double.IsInfinity(value)) { - case QuantityFamily.Length: return value.FromLength(spec.Unit); - case QuantityFamily.Area: return value.FromArea(spec.Unit); - case QuantityFamily.Volume: return value.FromVolume(spec.Unit); - case QuantityFamily.AreaMomentOfInertia: return value.FromAreaMomentOfInertia(spec.Unit); - case QuantityFamily.Pressure: return value.FromPressure(spec.Unit); - case QuantityFamily.Force: return value.FromForce(spec.Unit); - case QuantityFamily.Torque: return value.FromTorque(spec.Unit); - case QuantityFamily.ForcePerLength: return value.FromForcePerLength(spec.Unit); - case QuantityFamily.Angle: return value.FromAngle(spec.Unit); - case QuantityFamily.Mass: return value.FromMass(spec.Unit); - case QuantityFamily.Acceleration: return value.FromAcceleration(spec.Unit); - case QuantityFamily.Density: return value.FromDensity(spec.Unit); - case QuantityFamily.Energy: return value.FromEnergy(spec.Unit); - case QuantityFamily.Speed: return value.FromSpeed(spec.Unit); - case QuantityFamily.Temperature: return value.FromTemperature(spec.Unit); - case QuantityFamily.Time: return value.FromDuration(spec.Unit); - case QuantityFamily.None: return value; - default: return double.NaN; + Compute.RecordError("Quantity is not a real number."); + return double.NaN; } + + if (UN.UnitConverter.TryConvert(value, fromUnit, toUnit, out double result)) + return result; + + Compute.RecordError($"No conversion is available between '{unitSymbol}' and its SI unit."); + return double.NaN; } + + /***************************************************/ } } diff --git a/Units_Engine/Convert/ToUnit.cs b/Units_Engine/Convert/ToUnit.cs index 21485d6..286c483 100644 --- a/Units_Engine/Convert/ToUnit.cs +++ b/Units_Engine/Convert/ToUnit.cs @@ -28,9 +28,13 @@ namespace BH.Engine.Units { public static partial class Convert { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + [Description("Converts an SI value to the given unit symbol, e.g. 0.012 m → 12 \"mm\".")] [Input("siValue", "The value in SI units.")] - [Input("unitSymbol", "Unit symbol to convert to (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] + [Input("unitSymbol", "Unit symbol to convert to (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive. An empty symbol or \"-\" leaves the value unchanged.")] [Output("value", "The value in the specified unit, or NaN if the unit is unrecognised.")] public static double ToUnit(this double siValue, string unitSymbol) { @@ -38,32 +42,12 @@ public static double ToUnit(this double siValue, string unitSymbol) if (spec == null) return double.NaN; - return ToUnit(siValue, spec); - } + if (spec.Unit == null) + return siValue; - private static double ToUnit(double siValue, UnitSpec spec) - { - switch (spec.Family) - { - case QuantityFamily.Length: return siValue.ToLength(spec.Unit); - case QuantityFamily.Area: return siValue.ToArea(spec.Unit); - case QuantityFamily.Volume: return siValue.ToVolume(spec.Unit); - case QuantityFamily.AreaMomentOfInertia: return siValue.ToAreaMomentOfInertia(spec.Unit); - case QuantityFamily.Pressure: return siValue.ToPressure(spec.Unit); - case QuantityFamily.Force: return siValue.ToForce(spec.Unit); - case QuantityFamily.Torque: return siValue.ToTorque(spec.Unit); - case QuantityFamily.ForcePerLength: return siValue.ToForcePerLength(spec.Unit); - case QuantityFamily.Angle: return siValue.ToAngle(spec.Unit); - case QuantityFamily.Mass: return siValue.ToMass(spec.Unit); - case QuantityFamily.Acceleration: return siValue.ToAcceleration(spec.Unit); - case QuantityFamily.Density: return siValue.ToDensity(spec.Unit); - case QuantityFamily.Energy: return siValue.ToEnergy(spec.Unit); - case QuantityFamily.Speed: return siValue.ToSpeed(spec.Unit); - case QuantityFamily.Temperature: return siValue.ToTemperature(spec.Unit); - case QuantityFamily.Time: return siValue.ToDuration(spec.Unit); - case QuantityFamily.None: return siValue; - default: return double.NaN; - } + return ConvertUnit(siValue, spec.SIUnit, spec.Unit, unitSymbol); } + + /***************************************************/ } -} \ No newline at end of file +} diff --git a/Units_Engine/Query/ResolveUnit.cs b/Units_Engine/Query/ResolveUnit.cs index e8053fe..469fe3a 100644 --- a/Units_Engine/Query/ResolveUnit.cs +++ b/Units_Engine/Query/ResolveUnit.cs @@ -23,6 +23,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes using UNU = UnitsNet.Units; @@ -40,14 +41,14 @@ public static partial class Query /**** Public Methods ****/ /***************************************************/ - [Description("Resolves a unit symbol string to its corresponding UnitSpec, identifying the quantity family and unit.")] + [Description("Resolves a unit symbol string to its corresponding UnitSpec, identifying the unit and the SI unit its quantity converts to.")] [Input("unitSymbol", "Unit symbol to resolve (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] [Output("unitSpec", "The resolved UnitSpec, or null if the unit is unrecognised.")] public static UnitSpec ResolveUnit(string unitSymbol) { string key = unitSymbol?.Trim() ?? ""; if (key == "" || key == "-") - return new UnitSpec { Family = QuantityFamily.None, Unit = null }; + return new UnitSpec(); if (m_UnitTable.TryGetValue(key, out UnitSpec spec)) return spec; @@ -64,35 +65,51 @@ private static Dictionary BuildUnitTable() { var table = new Dictionary(StringComparer.Ordinal); - foreach (var family in m_Families) + foreach (Enum siUnit in m_SIUnits) { - foreach (object unit in Enum.GetValues(family.Key)) + UN.QuantityInfo quantityInfo = UN.Quantity.Infos.FirstOrDefault(x => x.UnitType == siUnit.GetType()); + if (quantityInfo == null) + continue; + + foreach (UN.UnitInfo unitInfo in quantityInfo.UnitInfos) { - foreach (string symbol in GetAbbreviations(family.Key, (int)(object)unit)) + foreach (string symbol in GetAbbreviations(unitInfo)) { - TryAdd(table, symbol, family.Value, unit); - TryAdd(table, Ascii(symbol), family.Value, unit); + TryAdd(table, symbol, unitInfo, siUnit); + TryAdd(table, Ascii(symbol), unitInfo, siUnit); } } } // Torque aliases UnitsNet doesn't publish - TryAdd(table, "Nm", QuantityFamily.Torque, UNU.TorqueUnit.NewtonMeter); - TryAdd(table, "N.m", QuantityFamily.Torque, UNU.TorqueUnit.NewtonMeter); - TryAdd(table, "kNm", QuantityFamily.Torque, UNU.TorqueUnit.KilonewtonMeter); - TryAdd(table, "kN.m", QuantityFamily.Torque, UNU.TorqueUnit.KilonewtonMeter); + UN.UnitInfo newtonMetre = UN.Quantity.GetUnitInfo(UNU.TorqueUnit.NewtonMeter); + UN.UnitInfo kilonewtonMetre = UN.Quantity.GetUnitInfo(UNU.TorqueUnit.KilonewtonMeter); + + TryAdd(table, "Nm", newtonMetre, UNU.TorqueUnit.NewtonMeter); + TryAdd(table, "N.m", newtonMetre, UNU.TorqueUnit.NewtonMeter); + TryAdd(table, "kNm", kilonewtonMetre, UNU.TorqueUnit.NewtonMeter); + TryAdd(table, "kN.m", kilonewtonMetre, UNU.TorqueUnit.NewtonMeter); + + // Symbols that more than one quantity claims, forced to the reading expected in a building + // engineering context. Left to the loop above, each of these lands on a unit that is never + // the one intended here. The remaining overlaps the loop resolves acceptably on its own: + // "g" to gram, "mg" to milligram, "MN" to meganewton, "kt" to kilotonne, "mil" to mil, + // "m" to metre, "'" to foot and the double prime to inch. + Set(table, "t", UNU.MassUnit.Tonne, UNU.MassUnit.Kilogram); // not Volume.MetricTeaspoon + Set(table, "h", UNU.DurationUnit.Hour, UNU.DurationUnit.Second); // not Length.Hand + Set(table, "min", UNU.DurationUnit.Minute, UNU.DurationUnit.Second); // not Angle.Arcminute + Set(table, "sec", UNU.DurationUnit.Second, UNU.DurationUnit.Second); // not Angle.Arcsecond return table; } /***************************************************/ - private static IEnumerable GetAbbreviations(Type unitType, int unitValue) + private static IEnumerable GetAbbreviations(UN.UnitInfo unitInfo) { try { - return UN.UnitsNetSetup.Default.UnitAbbreviations - .GetUnitAbbreviations(unitType, unitValue, CultureInfo.InvariantCulture); + return UN.UnitsNetSetup.Default.UnitAbbreviations.GetAbbreviations(unitInfo, CultureInfo.InvariantCulture); } catch { @@ -102,11 +119,32 @@ private static IEnumerable GetAbbreviations(Type unitType, int unitValue /***************************************************/ + // Claims a symbol for a unit, leaving any earlier claim on that symbol in place. private static void TryAdd(Dictionary table, string symbol, - QuantityFamily family, object unit) + UN.UnitInfo unitInfo, Enum siUnit) { if (!string.IsNullOrWhiteSpace(symbol) && !table.ContainsKey(symbol)) - table[symbol] = new UnitSpec { Family = family, Unit = unit }; + table[symbol] = Spec(unitInfo, siUnit); + } + + /***************************************************/ + + // Claims a symbol for a unit, overriding any earlier claim on that symbol. + private static void Set(Dictionary table, string symbol, Enum unit, Enum siUnit) + { + table[symbol] = Spec(UN.Quantity.GetUnitInfo(unit), siUnit); + } + + /***************************************************/ + + private static UnitSpec Spec(UN.UnitInfo unitInfo, Enum siUnit) + { + return new UnitSpec + { + Unit = unitInfo.Value, + SIUnit = siUnit, + QuantityName = unitInfo.QuantityName + }; } /***************************************************/ @@ -124,22 +162,40 @@ private static string Ascii(string symbol) /**** Private Fields ****/ /***************************************************/ - private static readonly Dictionary m_Families = new Dictionary + // The quantities recognised by ResolveUnit, each represented by the SI unit it converts to and from. + // The unit type of the quantity is taken from the entry itself, so adding a quantity is a single line. + // These are the SI units used by the corresponding BHoM Convert methods, which is not always the UnitsNet + // base unit - notably Temperature, where the BHoM convention is degrees Celsius rather than Kelvin. + // Order matters: where two quantities publish the same unit symbol, the first entry to claim it wins. + // Mass precedes Angle and Acceleration so that "g" resolves to gram rather than gradian or standard gravity. + private static readonly Enum[] m_SIUnits = new Enum[] { - { typeof(UNU.LengthUnit), QuantityFamily.Length }, - { typeof(UNU.AreaUnit), QuantityFamily.Area }, - { typeof(UNU.VolumeUnit), QuantityFamily.Volume }, - { typeof(UNU.AreaMomentOfInertiaUnit), QuantityFamily.AreaMomentOfInertia }, - { typeof(UNU.PressureUnit), QuantityFamily.Pressure }, - { typeof(UNU.ForceUnit), QuantityFamily.Force }, - { typeof(UNU.TorqueUnit), QuantityFamily.Torque }, - { typeof(UNU.ForcePerLengthUnit), QuantityFamily.ForcePerLength }, - { typeof(UNU.AngleUnit), QuantityFamily.Angle }, - { typeof(UNU.MassUnit), QuantityFamily.Mass }, + UNU.LengthUnit.Meter, + UNU.AreaUnit.SquareMeter, + UNU.VolumeUnit.CubicMeter, + UNU.AreaMomentOfInertiaUnit.MeterToTheFourth, + UNU.PressureUnit.Pascal, + UNU.ForceUnit.Newton, + UNU.TorqueUnit.NewtonMeter, + UNU.ForcePerLengthUnit.NewtonPerMeter, + UNU.TorquePerLengthUnit.NewtonMeterPerMeter, + UNU.MassUnit.Kilogram, + UNU.AngleUnit.Radian, + UNU.AccelerationUnit.MeterPerSecondSquared, + UNU.DensityUnit.KilogramPerCubicMeter, + UNU.EnergyUnit.Joule, + UNU.SpeedUnit.MeterPerSecond, + UNU.DurationUnit.Second, + UNU.TemperatureUnit.DegreeCelsius, + UNU.TemperatureDeltaUnit.Kelvin, + UNU.CoefficientOfThermalExpansionUnit.PerKelvin, + UNU.ElectricConductivityUnit.SiemensPerMeter, + UNU.MassFractionUnit.KilogramPerKilogram, + UNU.MolalityUnit.MolePerKilogram, }; private static readonly Dictionary m_UnitTable = BuildUnitTable(); /***************************************************/ } -} \ No newline at end of file +} diff --git a/Units_oM/Enums/QuantityFamily.cs b/Units_oM/Enums/QuantityFamily.cs deleted file mode 100644 index cff33ab..0000000 --- a/Units_oM/Enums/QuantityFamily.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using System.ComponentModel; - -namespace BH.oM.Units -{ - [Description("Categorises physical quantities for dispatch to the correct conversion method.")] - public enum QuantityFamily - { - None = 0, - Length = 1, - Area = 2, - Volume = 3, - AreaMomentOfInertia = 4, - Pressure = 5, - Force = 6, - Torque = 7, - ForcePerLength = 8, - Angle = 9, - Mass = 10, - Acceleration = 11, - Density = 12, - Energy = 13, - Power = 14, - Speed = 15, - Temperature = 16, - Time = 17, - } -} diff --git a/Units_oM/UnitSpec.cs b/Units_oM/UnitSpec.cs index af4c25e..449f3df 100644 --- a/Units_oM/UnitSpec.cs +++ b/Units_oM/UnitSpec.cs @@ -20,14 +20,21 @@ * along with this code. If not, see . */ +using System; using System.ComponentModel; namespace BH.oM.Units { - [Description("Specification linking a unit symbol to its quantity family and unit enumeration value.")] + [Description("Specification linking a unit symbol to its unit enumeration value and the SI unit its quantity converts to.")] public class UnitSpec { - public virtual QuantityFamily Family { get; set; } = QuantityFamily.None; - public virtual object Unit { get; set; } = null; + [Description("The resolved unit. Null for a dimensionless value, in which case no conversion is applied.")] + public virtual Enum Unit { get; set; } = null; + + [Description("The SI unit that this quantity converts to and from, as defined by the BHoM convention for the quantity.")] + public virtual Enum SIUnit { get; set; } = null; + + [Description("Name of the quantity the unit belongs to, e.g. \"Force\". Empty for a dimensionless value.")] + public virtual string QuantityName { get; set; } = ""; } -} \ No newline at end of file +} From 375292f961e01e6f8b89e85ec79e5568c8a5101d Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Tue, 1 Sep 2026 17:27:09 +0100 Subject: [PATCH 05/14] Use Enum overload for To/FromUnit --- Units_Engine/Convert/FromUnit.cs | 130 +++++++++++++++++++++++++++++- Units_Engine/Convert/ToUnit.cs | 52 +++++++++++- Units_Engine/Query/ResolveUnit.cs | 30 +++++++ Units_oM/UnitSpec.cs | 8 +- 4 files changed, 214 insertions(+), 6 deletions(-) diff --git a/Units_Engine/Convert/FromUnit.cs b/Units_Engine/Convert/FromUnit.cs index e769d63..4e71f2a 100644 --- a/Units_Engine/Convert/FromUnit.cs +++ b/Units_Engine/Convert/FromUnit.cs @@ -21,10 +21,11 @@ */ using System; +using System.Collections.Generic; +using System.ComponentModel; using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes -using System.ComponentModel; using BH.oM.Base.Attributes; using BH.oM.Units; using BH.Engine.Base; @@ -37,6 +38,54 @@ public static partial class Convert /**** Public Methods ****/ /***************************************************/ + [Description("Converts a value from the given unit to SI, e.g. 12 LengthUnit.Millimeter → 0.012 m. " + + "The inverse of ToUnit.")] + [Input("value", "The value in the given unit.")] + [Input("unit", "The unit the value is in, as a member of one of the BH.oM.Units unit enums, e.g. " + + "LengthUnit.Millimeter. A UnitsNet unit is read as well, but records a warning.")] + [Output("siValue", "The value in SI units, or NaN when the unit has no conversion.")] + public static double FromUnit(this double value, Enum unit) + { + Enum bhomUnit = BHoMUnit(unit); + if (bhomUnit == null) + return double.NaN; + + // The unit's type names its quantity, so the type is the whole of the dispatch. A symbol that two + // quantities both publish - "t" for both a tonne and a teaspoon - cannot arise here as it does + // when the unit arrives as text, because the caller has already said which quantity it means. + switch (bhomUnit.GetType().Name) + { + case nameof(LengthUnit): return value.FromLength(bhomUnit); + case nameof(AreaUnit): return value.FromArea(bhomUnit); + case nameof(VolumeUnit): return value.FromVolume(bhomUnit); + case nameof(AreaMomentOfInertiaUnit): return value.FromAreaMomentOfInertia(bhomUnit); + case nameof(PressureUnit): return value.FromPressure(bhomUnit); + case nameof(ForceUnit): return value.FromForce(bhomUnit); + case nameof(TorqueUnit): return value.FromTorque(bhomUnit); + case nameof(ForcePerLengthUnit): return value.FromForcePerLength(bhomUnit); + case nameof(TorquePerLengthUnit): return value.FromMomentPerLength(bhomUnit); + case nameof(MassUnit): return value.FromMass(bhomUnit); + case nameof(AngleUnit): return value.FromAngle(bhomUnit); + case nameof(AccelerationUnit): return value.FromAcceleration(bhomUnit); + case nameof(DensityUnit): return value.FromDensity(bhomUnit); + case nameof(EnergyUnit): return value.FromEnergy(bhomUnit); + case nameof(SpeedUnit): return value.FromSpeed(bhomUnit); + case nameof(DurationUnit): return value.FromDuration(bhomUnit); + case nameof(TemperatureUnit): return value.FromTemperature(bhomUnit); + case nameof(TemperatureDeltaUnit): return value.FromTemperatureDelta(bhomUnit); + case nameof(CoefficientOfThermalExpansionUnit): return value.FromCoefficientOfThermalExpansion(bhomUnit); + case nameof(ElectricConductivityUnit): return value.FromElectricConductivity(bhomUnit); + case nameof(MassFractionUnit): return value.FromMassFraction(bhomUnit); + case nameof(MolalityUnit): return value.FromMolality(bhomUnit); + + default: + Compute.RecordError($"BH.Engine.Units has no conversion for a {bhomUnit.GetType().Name}."); + return double.NaN; + } + } + + /***************************************************/ + [Description("Converts a value from the given unit symbol to SI, e.g. 12 \"mm\" → 0.012 m.")] [Input("value", "The value in the specified unit.")] [Input("unitSymbol", "Unit symbol (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive. An empty symbol or \"-\" leaves the value unchanged.")] @@ -47,8 +96,10 @@ public static double FromUnit(this double value, string unitSymbol) if (spec == null) return double.NaN; + // A dimensionless unit carries no Unit and a Factor of 1, so it passes straight through; the + // units no quantity in UnitsNet can express carry a Factor instead of a Unit. if (spec.Unit == null) - return value; + return value * spec.Factor; return ConvertUnit(value, spec.Unit, spec.SIUnit, unitSymbol); } @@ -57,8 +108,72 @@ public static double FromUnit(this double value, string unitSymbol) /**** Private Methods ****/ /***************************************************/ - // Shared conversion step for FromUnit and ToUnit. The unit and its SI counterpart both come from the - // same UnitSpec, so the only difference between the two is which way round they are passed. + // Shared by both FromUnit and ToUnit overloads. BH.oM.Units.ForceUnit and UnitsNet.Units.ForceUnit + // share a Type.Name, so this has to run before the switch: a UnitsNet unit would otherwise match its + // case and then come back NaN from FromForce, which reads only BHoM units. + private static Enum BHoMUnit(Enum unit) + { + if (unit == null) + { + Compute.RecordError("No unit was given to convert with."); + return null; + } + + Enum bhomUnit = unit.GetType().Namespace == "BH.oM.Units" ? unit : ToBHoMUnit(unit); + if (bhomUnit == null) + return null; + + // Every BH.oM.Units enum carries one, and it names no unit. + if (bhomUnit.ToString() == "Undefined") + { + Compute.RecordError($"{bhomUnit.GetType().Name}.Undefined names no unit, so there is nothing to convert to."); + return null; + } + + return bhomUnit; + } + + /***************************************************/ + + // The bridge is by NAME, not value: the two enums' integer values disagree - BH.oM.Units.LengthUnit + // .Meter is 18 where UnitsNet's is 21 - so a cast would hand back a different unit entirely. + private static Enum ToBHoMUnit(Enum unit) + { + Type type = unit.GetType(); + + Compute.RecordWarning($"{type.FullName} is not a BHoM unit. Use BH.oM.Units.{type.Name}.{unit} " + + "instead - BH.Engine.Units converts BHoM units, and reads any other unit enum as a fallback only."); + + Type bhomType; + lock (m_BHoMUnitTypes) + { + if (!m_BHoMUnitTypes.TryGetValue(type, out bhomType)) + { + bhomType = typeof(LengthUnit).Assembly.GetType("BH.oM.Units." + type.Name); + m_BHoMUnitTypes[type] = bhomType; + } + } + + if (bhomType == null) + { + Compute.RecordError($"BH.oM.Units has no {type.Name}, so {unit} cannot be converted."); + return null; + } + + string name = unit.ToString(); + if (!Enum.IsDefined(bhomType, name)) + { + Compute.RecordError($"BH.oM.Units.{type.Name} has no {name}, so it cannot be converted."); + return null; + } + + return (Enum)Enum.Parse(bhomType, name); + } + + /***************************************************/ + + // Shared conversion step for the FromUnit and ToUnit symbol overloads. The unit and its SI counterpart + // both come from the same UnitSpec, so the only difference between the two is which way round they are passed. private static double ConvertUnit(double value, Enum fromUnit, Enum toUnit, string unitSymbol) { if (double.IsNaN(value) || double.IsInfinity(value)) @@ -74,6 +189,13 @@ private static double ConvertUnit(double value, Enum fromUnit, Enum toUnit, stri return double.NaN; } + /***************************************************/ + /**** Private Fields ****/ + /***************************************************/ + + // One reflection lookup per foreign unit enum type, not per call. + private static readonly Dictionary m_BHoMUnitTypes = new Dictionary(); + /***************************************************/ } } diff --git a/Units_Engine/Convert/ToUnit.cs b/Units_Engine/Convert/ToUnit.cs index 286c483..7d2f256 100644 --- a/Units_Engine/Convert/ToUnit.cs +++ b/Units_Engine/Convert/ToUnit.cs @@ -20,9 +20,12 @@ * along with this code. If not, see . */ +using System; using System.ComponentModel; + using BH.oM.Base.Attributes; using BH.oM.Units; +using BH.Engine.Base; namespace BH.Engine.Units { @@ -32,6 +35,52 @@ public static partial class Convert /**** Public Methods ****/ /***************************************************/ + [Description("Converts an SI value to the given unit, e.g. 0.012 m → 12 LengthUnit.Millimeter. " + + "The inverse of FromUnit.")] + [Input("siValue", "The value in SI units.")] + [Input("unit", "The unit to convert to, as a member of one of the BH.oM.Units unit enums, e.g. " + + "LengthUnit.Millimeter. A UnitsNet unit is read as well, but records a warning.")] + [Output("value", "The value in the given unit, or NaN when the unit has no conversion.")] + public static double ToUnit(this double siValue, Enum unit) + { + Enum bhomUnit = BHoMUnit(unit); + if (bhomUnit == null) + return double.NaN; + + // See FromUnit: the unit's type names its quantity, so the type is the whole of the dispatch. + switch (bhomUnit.GetType().Name) + { + case nameof(LengthUnit): return siValue.ToLength(bhomUnit); + case nameof(AreaUnit): return siValue.ToArea(bhomUnit); + case nameof(VolumeUnit): return siValue.ToVolume(bhomUnit); + case nameof(AreaMomentOfInertiaUnit): return siValue.ToAreaMomentOfInertia(bhomUnit); + case nameof(PressureUnit): return siValue.ToPressure(bhomUnit); + case nameof(ForceUnit): return siValue.ToForce(bhomUnit); + case nameof(TorqueUnit): return siValue.ToTorque(bhomUnit); + case nameof(ForcePerLengthUnit): return siValue.ToForcePerLength(bhomUnit); + case nameof(TorquePerLengthUnit): return siValue.ToMomentPerLength(bhomUnit); + case nameof(MassUnit): return siValue.ToMass(bhomUnit); + case nameof(AngleUnit): return siValue.ToAngle(bhomUnit); + case nameof(AccelerationUnit): return siValue.ToAcceleration(bhomUnit); + case nameof(DensityUnit): return siValue.ToDensity(bhomUnit); + case nameof(EnergyUnit): return siValue.ToEnergy(bhomUnit); + case nameof(SpeedUnit): return siValue.ToSpeed(bhomUnit); + case nameof(DurationUnit): return siValue.ToDuration(bhomUnit); + case nameof(TemperatureUnit): return siValue.ToTemperature(bhomUnit); + case nameof(TemperatureDeltaUnit): return siValue.ToTemperatureDelta(bhomUnit); + case nameof(CoefficientOfThermalExpansionUnit): return siValue.ToCoefficientOfThermalExpansion(bhomUnit); + case nameof(ElectricConductivityUnit): return siValue.ToElectricConductivity(bhomUnit); + case nameof(MassFractionUnit): return siValue.ToMassFraction(bhomUnit); + case nameof(MolalityUnit): return siValue.ToMolality(bhomUnit); + + default: + Compute.RecordError($"BH.Engine.Units has no conversion for a {bhomUnit.GetType().Name}."); + return double.NaN; + } + } + + /***************************************************/ + [Description("Converts an SI value to the given unit symbol, e.g. 0.012 m → 12 \"mm\".")] [Input("siValue", "The value in SI units.")] [Input("unitSymbol", "Unit symbol to convert to (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive. An empty symbol or \"-\" leaves the value unchanged.")] @@ -42,8 +91,9 @@ public static double ToUnit(this double siValue, string unitSymbol) if (spec == null) return double.NaN; + // FromUnit multiplies by the factor to reach SI, so coming back the other way divides by it. if (spec.Unit == null) - return siValue; + return siValue / spec.Factor; return ConvertUnit(siValue, spec.SIUnit, spec.Unit, unitSymbol); } diff --git a/Units_Engine/Query/ResolveUnit.cs b/Units_Engine/Query/ResolveUnit.cs index 469fe3a..e021896 100644 --- a/Units_Engine/Query/ResolveUnit.cs +++ b/Units_Engine/Query/ResolveUnit.cs @@ -100,6 +100,20 @@ private static Dictionary BuildUnitTable() Set(table, "min", UNU.DurationUnit.Minute, UNU.DurationUnit.Second); // not Angle.Arcminute Set(table, "sec", UNU.DurationUnit.Second, UNU.DurationUnit.Second); // not Angle.Arcsecond + // Units no UnitsNet quantity can express, carried as a plain multiplier to SI instead of a unit. + // A warping constant is the sixth power of a length, and UnitsNet stops at the fourth; section + // tables publish it in dm6 in metric practice and in6 in US practice, so it follows the region + // rather than the length family, which is why all three spellings have to read. + AddFactored(table, "dm⁶", c_DecimetreToTheSixthFactor); + AddFactored(table, "dm6", c_DecimetreToTheSixthFactor); + AddFactored(table, "m⁶", 1.0); + AddFactored(table, "m6", 1.0); + AddFactored(table, "in⁶", m_InchToTheSixthFactor); + AddFactored(table, "in6", m_InchToTheSixthFactor); + + // UnitsNet publishes "%" only as a MassFraction, which BH.oM.Units has no member for. + AddFactored(table, "%", c_PercentFactor); + return table; } @@ -137,6 +151,15 @@ private static void Set(Dictionary table, string symbol, Enum /***************************************************/ + // Claims a symbol for a plain multiplier to SI, leaving any earlier claim on that symbol in place. + private static void AddFactored(Dictionary table, string symbol, double toSIFactor) + { + if (!table.ContainsKey(symbol)) + table[symbol] = new UnitSpec { Factor = toSIFactor }; + } + + /***************************************************/ + private static UnitSpec Spec(UN.UnitInfo unitInfo, Enum siUnit) { return new UnitSpec @@ -194,6 +217,13 @@ private static string Ascii(string symbol) UNU.MolalityUnit.MolePerKilogram, }; + private const double c_DecimetreToTheSixthFactor = 1e-6; + private const double c_PercentFactor = 0.01; + + // Taken from LengthUnit.Inch rather than written out, so it cannot drift from the inch the rest of + // the toolkit converts with. + private static readonly double m_InchToTheSixthFactor = 1.0 / Math.Pow(1.0.ToLength(LengthUnit.Inch), 6); + private static readonly Dictionary m_UnitTable = BuildUnitTable(); /***************************************************/ diff --git a/Units_oM/UnitSpec.cs b/Units_oM/UnitSpec.cs index 449f3df..bb41499 100644 --- a/Units_oM/UnitSpec.cs +++ b/Units_oM/UnitSpec.cs @@ -28,7 +28,8 @@ namespace BH.oM.Units [Description("Specification linking a unit symbol to its unit enumeration value and the SI unit its quantity converts to.")] public class UnitSpec { - [Description("The resolved unit. Null for a dimensionless value, in which case no conversion is applied.")] + [Description("The resolved unit. Null for a dimensionless value and for a unit no UnitsNet quantity " + + "can express, in which case Factor is applied instead.")] public virtual Enum Unit { get; set; } = null; [Description("The SI unit that this quantity converts to and from, as defined by the BHoM convention for the quantity.")] @@ -36,5 +37,10 @@ public class UnitSpec [Description("Name of the quantity the unit belongs to, e.g. \"Force\". Empty for a dimensionless value.")] public virtual string QuantityName { get; set; } = ""; + + [Description("Multiplier taking a value in this unit to SI, read only when Unit is null. 1 for a " + + "dimensionless value; otherwise the conversion for a unit UnitsNet has no quantity for, such as " + + "the sixth power of a length a warping constant is measured in.")] + public virtual double Factor { get; set; } = 1.0; } } From d3c3d4a9110887c64353df58fb564fc69b422937 Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Tue, 1 Sep 2026 22:45:42 +0100 Subject: [PATCH 06/14] Add WarpingMomentofInertia and clean To/FromUnits methods --- Units_Engine/Convert/FromUnit.cs | 57 +---- Units_Engine/Convert/ToUnit.cs | 29 +-- .../CentimetreToTheSixth.cs | 62 +++++ .../DecimetreToTheSixth.cs | 62 +++++ .../WarpingMomentOfInertia/FootToTheSixth.cs | 62 +++++ .../WarpingMomentOfInertia/InchToTheSixth.cs | 62 +++++ .../MillimetreToTheSixth.cs | 62 +++++ .../WarpingMomentOfInertia.cs | 124 ++++++++++ Units_Engine/Query/ResolveUnit.cs | 231 ------------------ Units_Engine/Query/UnitSymbol.cs | 127 ++++++++++ Units_oM/Enums/WarpingMomentOfInertiaUnit.cs | 43 ++++ Units_oM/UnitSpec.cs | 46 ---- 12 files changed, 622 insertions(+), 345 deletions(-) create mode 100644 Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs create mode 100644 Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs create mode 100644 Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs create mode 100644 Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs create mode 100644 Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs create mode 100644 Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs delete mode 100644 Units_Engine/Query/ResolveUnit.cs create mode 100644 Units_Engine/Query/UnitSymbol.cs create mode 100644 Units_oM/Enums/WarpingMomentOfInertiaUnit.cs delete mode 100644 Units_oM/UnitSpec.cs diff --git a/Units_Engine/Convert/FromUnit.cs b/Units_Engine/Convert/FromUnit.cs index 4e71f2a..fc6d87f 100644 --- a/Units_Engine/Convert/FromUnit.cs +++ b/Units_Engine/Convert/FromUnit.cs @@ -24,8 +24,6 @@ using System.Collections.Generic; using System.ComponentModel; -using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes - using BH.oM.Base.Attributes; using BH.oM.Units; using BH.Engine.Base; @@ -46,13 +44,18 @@ public static partial class Convert [Output("siValue", "The value in SI units, or NaN when the unit has no conversion.")] public static double FromUnit(this double value, Enum unit) { + // No unit is how a dimensionless quantity arrives - a Ratio or a Strain. Nothing to convert, + // so the value passes straight through. + if (unit == null) + return value; + Enum bhomUnit = BHoMUnit(unit); if (bhomUnit == null) return double.NaN; - // The unit's type names its quantity, so the type is the whole of the dispatch. A symbol that two - // quantities both publish - "t" for both a tonne and a teaspoon - cannot arise here as it does - // when the unit arrives as text, because the caller has already said which quantity it means. + // The unit's type names its quantity, so the type is the whole of the dispatch. This is why the + // unit travels as an enum and not as a symbol: a symbol two quantities both publish - "t" for + // both a tonne and a teaspoon - would have to be guessed at, where a type cannot be mistaken. switch (bhomUnit.GetType().Name) { case nameof(LengthUnit): return value.FromLength(bhomUnit); @@ -77,6 +80,7 @@ public static double FromUnit(this double value, Enum unit) case nameof(ElectricConductivityUnit): return value.FromElectricConductivity(bhomUnit); case nameof(MassFractionUnit): return value.FromMassFraction(bhomUnit); case nameof(MolalityUnit): return value.FromMolality(bhomUnit); + case nameof(WarpingMomentOfInertiaUnit): return value.FromWarpingMomentOfInertia(bhomUnit); default: Compute.RecordError($"BH.Engine.Units has no conversion for a {bhomUnit.GetType().Name}."); @@ -84,26 +88,6 @@ public static double FromUnit(this double value, Enum unit) } } - /***************************************************/ - - [Description("Converts a value from the given unit symbol to SI, e.g. 12 \"mm\" → 0.012 m.")] - [Input("value", "The value in the specified unit.")] - [Input("unitSymbol", "Unit symbol (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive. An empty symbol or \"-\" leaves the value unchanged.")] - [Output("siValue", "The value in SI units, or NaN if the unit is unrecognised.")] - public static double FromUnit(this double value, string unitSymbol) - { - UnitSpec spec = Query.ResolveUnit(unitSymbol); - if (spec == null) - return double.NaN; - - // A dimensionless unit carries no Unit and a Factor of 1, so it passes straight through; the - // units no quantity in UnitsNet can express carry a Factor instead of a Unit. - if (spec.Unit == null) - return value * spec.Factor; - - return ConvertUnit(value, spec.Unit, spec.SIUnit, unitSymbol); - } - /***************************************************/ /**** Private Methods ****/ /***************************************************/ @@ -113,12 +97,6 @@ public static double FromUnit(this double value, string unitSymbol) // case and then come back NaN from FromForce, which reads only BHoM units. private static Enum BHoMUnit(Enum unit) { - if (unit == null) - { - Compute.RecordError("No unit was given to convert with."); - return null; - } - Enum bhomUnit = unit.GetType().Namespace == "BH.oM.Units" ? unit : ToBHoMUnit(unit); if (bhomUnit == null) return null; @@ -172,23 +150,6 @@ private static Enum ToBHoMUnit(Enum unit) /***************************************************/ - // Shared conversion step for the FromUnit and ToUnit symbol overloads. The unit and its SI counterpart - // both come from the same UnitSpec, so the only difference between the two is which way round they are passed. - private static double ConvertUnit(double value, Enum fromUnit, Enum toUnit, string unitSymbol) - { - if (double.IsNaN(value) || double.IsInfinity(value)) - { - Compute.RecordError("Quantity is not a real number."); - return double.NaN; - } - - if (UN.UnitConverter.TryConvert(value, fromUnit, toUnit, out double result)) - return result; - - Compute.RecordError($"No conversion is available between '{unitSymbol}' and its SI unit."); - return double.NaN; - } - /***************************************************/ /**** Private Fields ****/ /***************************************************/ diff --git a/Units_Engine/Convert/ToUnit.cs b/Units_Engine/Convert/ToUnit.cs index 7d2f256..adb5307 100644 --- a/Units_Engine/Convert/ToUnit.cs +++ b/Units_Engine/Convert/ToUnit.cs @@ -43,11 +43,18 @@ public static partial class Convert [Output("value", "The value in the given unit, or NaN when the unit has no conversion.")] public static double ToUnit(this double siValue, Enum unit) { + // No unit is how a dimensionless quantity arrives - a Ratio or a Strain. Nothing to convert, + // so the value passes straight through. + if (unit == null) + return siValue; + Enum bhomUnit = BHoMUnit(unit); if (bhomUnit == null) return double.NaN; - // See FromUnit: the unit's type names its quantity, so the type is the whole of the dispatch. + // The unit's type names its quantity, so the type is the whole of the dispatch. This is why the + // unit travels as an enum and not as a symbol: a symbol two quantities both publish - "t" for + // both a tonne and a teaspoon - would have to be guessed at, where a type cannot be mistaken. switch (bhomUnit.GetType().Name) { case nameof(LengthUnit): return siValue.ToLength(bhomUnit); @@ -72,6 +79,7 @@ public static double ToUnit(this double siValue, Enum unit) case nameof(ElectricConductivityUnit): return siValue.ToElectricConductivity(bhomUnit); case nameof(MassFractionUnit): return siValue.ToMassFraction(bhomUnit); case nameof(MolalityUnit): return siValue.ToMolality(bhomUnit); + case nameof(WarpingMomentOfInertiaUnit): return siValue.ToWarpingMomentOfInertia(bhomUnit); default: Compute.RecordError($"BH.Engine.Units has no conversion for a {bhomUnit.GetType().Name}."); @@ -80,24 +88,5 @@ public static double ToUnit(this double siValue, Enum unit) } /***************************************************/ - - [Description("Converts an SI value to the given unit symbol, e.g. 0.012 m → 12 \"mm\".")] - [Input("siValue", "The value in SI units.")] - [Input("unitSymbol", "Unit symbol to convert to (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive. An empty symbol or \"-\" leaves the value unchanged.")] - [Output("value", "The value in the specified unit, or NaN if the unit is unrecognised.")] - public static double ToUnit(this double siValue, string unitSymbol) - { - UnitSpec spec = Query.ResolveUnit(unitSymbol); - if (spec == null) - return double.NaN; - - // FromUnit multiplies by the factor to reach SI, so coming back the other way divides by it. - if (spec.Unit == null) - return siValue / spec.Factor; - - return ConvertUnit(siValue, spec.SIUnit, spec.Unit, unitSymbol); - } - - /***************************************************/ } } diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs new file mode 100644 index 0000000..d678eca --- /dev/null +++ b/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs @@ -0,0 +1,62 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UnitsNet.Units; + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Quantities.Attributes; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Convert SI units (metres to the sixth) into centimetres to the sixth")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] + [Output("centimetresToTheSixth", "The number of centimetres to the sixth")] + public static double ToCentimetreToTheSixth(this double metresToTheSixth) + { + UN.QuantityValue qv = metresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.CentimeterToTheSixth); + } + + [Description("Convert centimetres to the sixth into SI units (metres to the sixth)")] + [Input("centimetresToTheSixth", "The number of centimetres to the sixth to convert")] + [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + public static double FromCentimetreToTheSixth(this double centimetresToTheSixth) + { + UN.QuantityValue qv = centimetresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.CentimeterToTheSixth, WarpingMomentOfInertiaUnit.MeterToTheSixth); + } + } +} + + + + diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs new file mode 100644 index 0000000..98b1922 --- /dev/null +++ b/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs @@ -0,0 +1,62 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UnitsNet.Units; + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Quantities.Attributes; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Convert SI units (metres to the sixth) into decimetres to the sixth")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] + [Output("decimetresToTheSixth", "The number of decimetres to the sixth")] + public static double ToDecimetreToTheSixth(this double metresToTheSixth) + { + UN.QuantityValue qv = metresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.DecimeterToTheSixth); + } + + [Description("Convert decimetres to the sixth into SI units (metres to the sixth)")] + [Input("decimetresToTheSixth", "The number of decimetres to the sixth to convert")] + [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + public static double FromDecimetreToTheSixth(this double decimetresToTheSixth) + { + UN.QuantityValue qv = decimetresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.DecimeterToTheSixth, WarpingMomentOfInertiaUnit.MeterToTheSixth); + } + } +} + + + + diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs new file mode 100644 index 0000000..7e0a2f5 --- /dev/null +++ b/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs @@ -0,0 +1,62 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UnitsNet.Units; + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Quantities.Attributes; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Convert SI units (metres to the sixth) into feet to the sixth")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] + [Output("feetToTheSixth", "The number of feet to the sixth")] + public static double ToFootToTheSixth(this double metresToTheSixth) + { + UN.QuantityValue qv = metresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.FootToTheSixth); + } + + [Description("Convert feet to the sixth into SI units (metres to the sixth)")] + [Input("feetToTheSixth", "The number of feet to the sixth to convert")] + [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + public static double FromFootToTheSixth(this double feetToTheSixth) + { + UN.QuantityValue qv = feetToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.FootToTheSixth, WarpingMomentOfInertiaUnit.MeterToTheSixth); + } + } +} + + + + diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs new file mode 100644 index 0000000..bc15820 --- /dev/null +++ b/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs @@ -0,0 +1,62 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UnitsNet.Units; + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Quantities.Attributes; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Convert SI units (metres to the sixth) into inches to the sixth")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] + [Output("inchesToTheSixth", "The number of inches to the sixth")] + public static double ToInchToTheSixth(this double metresToTheSixth) + { + UN.QuantityValue qv = metresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.InchToTheSixth); + } + + [Description("Convert inches to the sixth into SI units (metres to the sixth)")] + [Input("inchesToTheSixth", "The number of inches to the sixth to convert")] + [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + public static double FromInchToTheSixth(this double inchesToTheSixth) + { + UN.QuantityValue qv = inchesToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.InchToTheSixth, WarpingMomentOfInertiaUnit.MeterToTheSixth); + } + } +} + + + + diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs new file mode 100644 index 0000000..81f6eb0 --- /dev/null +++ b/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs @@ -0,0 +1,62 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UnitsNet.Units; + +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Quantities.Attributes; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + [Description("Convert SI units (metres to the sixth) into millimetres to the sixth")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] + [Output("millimetresToTheSixth", "The number of millimetres to the sixth")] + public static double ToMillimetreToTheSixth(this double metresToTheSixth) + { + UN.QuantityValue qv = metresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.MillimeterToTheSixth); + } + + [Description("Convert millimetres to the sixth into SI units (metres to the sixth)")] + [Input("millimetresToTheSixth", "The number of millimetres to the sixth to convert")] + [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + public static double FromMillimetreToTheSixth(this double millimetresToTheSixth) + { + UN.QuantityValue qv = millimetresToTheSixth; + return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MillimeterToTheSixth, WarpingMomentOfInertiaUnit.MeterToTheSixth); + } + } +} + + + + diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs b/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs new file mode 100644 index 0000000..525fb06 --- /dev/null +++ b/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs @@ -0,0 +1,124 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes +using UNU = UnitsNet.Units; +using System.ComponentModel; +using BH.oM.Base.Attributes; +using BH.oM.Units; +using BH.Engine.Base; + +namespace BH.Engine.Units +{ + public static partial class Convert + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("Convert a warping moment of inertia into SI units (metresToTheSixth).")] + [Input("warpingMomentOfInertia", "The quantity to convert.")] + [Input("unit", "The unit in which the quantity is defined. This can be a string, or you can use the BHoM Enum WarpingMomentOfInertiaUnit.")] + [Output("metresToTheSixth", "The equivalent number of metresToTheSixth.")] + public static double FromWarpingMomentOfInertia(this double warpingMomentOfInertia, object unit) + { + if (Double.IsNaN(warpingMomentOfInertia) || Double.IsInfinity(warpingMomentOfInertia)) + { + Compute.RecordError("Quantity is not a real number."); + return double.NaN; + } + + UN.QuantityValue qv = warpingMomentOfInertia; + UNU.WarpingMomentOfInertiaUnit unitSI = UNU.WarpingMomentOfInertiaUnit.MeterToTheSixth; + UNU.WarpingMomentOfInertiaUnit? unUnit = ToWarpingMomentOfInertiaUnit(unit); + + if (unUnit != null) + return UN.UnitConverter.Convert(qv, unUnit, unitSI); + + Compute.RecordError("Unit was undefined. Please use the appropriate BHoM Units Enum."); + return double.NaN; + } + + /***************************************************/ + + [Description("Convert SI units (metresToTheSixth) into another warping moment of inertia unit.")] + [Input("metresToTheSixth", "The number of metresToTheSixth to convert.")] + [Input("unit", "The unit to convert to. This can be a string, or you can use the BHoM Enum WarpingMomentOfInertiaUnit.")] + [Output("warpingMomentOfInertia", "The equivalent quantity defined in the specified unit.")] + public static double ToWarpingMomentOfInertia(this double metresToTheSixth, object unit) + { + if (Double.IsNaN(metresToTheSixth) || Double.IsInfinity(metresToTheSixth)) + { + Compute.RecordError("Quantity is not a real number."); + return double.NaN; + } + + UN.QuantityValue qv = metresToTheSixth; + UNU.WarpingMomentOfInertiaUnit unitSI = UNU.WarpingMomentOfInertiaUnit.MeterToTheSixth; + UNU.WarpingMomentOfInertiaUnit? unUnit = ToWarpingMomentOfInertiaUnit(unit); + + if (unUnit != null) + return UN.UnitConverter.Convert(qv, unitSI, unUnit); + + Compute.RecordError("Unit was undefined. Please use the appropriate BHoM Units Enum."); + return double.NaN; + } + + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + private static UNU.WarpingMomentOfInertiaUnit? ToWarpingMomentOfInertiaUnit(object unit) + { + if (unit == null || unit.ToString() == null) + return null; + + if (unit.GetType() == typeof(string)) + { + WarpingMomentOfInertiaUnit unitEnum; + if (Enum.TryParse(unit.ToString(), out unitEnum)) + unit = unitEnum; + else + unit = unit.ToString().ToLower(); + } + + switch (unit) + { + case WarpingMomentOfInertiaUnit.MillimeterToTheSixth: + return UNU.WarpingMomentOfInertiaUnit.MillimeterToTheSixth; + case WarpingMomentOfInertiaUnit.CentimeterToTheSixth: + return UNU.WarpingMomentOfInertiaUnit.CentimeterToTheSixth; + case WarpingMomentOfInertiaUnit.DecimeterToTheSixth: + return UNU.WarpingMomentOfInertiaUnit.DecimeterToTheSixth; + case WarpingMomentOfInertiaUnit.MeterToTheSixth: + return UNU.WarpingMomentOfInertiaUnit.MeterToTheSixth; + case WarpingMomentOfInertiaUnit.InchToTheSixth: + return UNU.WarpingMomentOfInertiaUnit.InchToTheSixth; + case WarpingMomentOfInertiaUnit.FootToTheSixth: + return UNU.WarpingMomentOfInertiaUnit.FootToTheSixth; + default: + return null; + } + } + } +} diff --git a/Units_Engine/Query/ResolveUnit.cs b/Units_Engine/Query/ResolveUnit.cs deleted file mode 100644 index e021896..0000000 --- a/Units_Engine/Query/ResolveUnit.cs +++ /dev/null @@ -1,231 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; - -using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes -using UNU = UnitsNet.Units; - -using System.ComponentModel; -using BH.oM.Base.Attributes; -using BH.oM.Units; -using BH.Engine.Base; - -namespace BH.Engine.Units -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("Resolves a unit symbol string to its corresponding UnitSpec, identifying the unit and the SI unit its quantity converts to.")] - [Input("unitSymbol", "Unit symbol to resolve (e.g. \"mm\", \"kN\", \"MPa\"). Case-sensitive.")] - [Output("unitSpec", "The resolved UnitSpec, or null if the unit is unrecognised.")] - public static UnitSpec ResolveUnit(string unitSymbol) - { - string key = unitSymbol?.Trim() ?? ""; - if (key == "" || key == "-") - return new UnitSpec(); - - if (m_UnitTable.TryGetValue(key, out UnitSpec spec)) - return spec; - - Compute.RecordError($"Unit '{unitSymbol}' is not recognised. Unit symbols are case-sensitive."); - return null; - } - - /***************************************************/ - /**** Private Methods ****/ - /***************************************************/ - - private static Dictionary BuildUnitTable() - { - var table = new Dictionary(StringComparer.Ordinal); - - foreach (Enum siUnit in m_SIUnits) - { - UN.QuantityInfo quantityInfo = UN.Quantity.Infos.FirstOrDefault(x => x.UnitType == siUnit.GetType()); - if (quantityInfo == null) - continue; - - foreach (UN.UnitInfo unitInfo in quantityInfo.UnitInfos) - { - foreach (string symbol in GetAbbreviations(unitInfo)) - { - TryAdd(table, symbol, unitInfo, siUnit); - TryAdd(table, Ascii(symbol), unitInfo, siUnit); - } - } - } - - // Torque aliases UnitsNet doesn't publish - UN.UnitInfo newtonMetre = UN.Quantity.GetUnitInfo(UNU.TorqueUnit.NewtonMeter); - UN.UnitInfo kilonewtonMetre = UN.Quantity.GetUnitInfo(UNU.TorqueUnit.KilonewtonMeter); - - TryAdd(table, "Nm", newtonMetre, UNU.TorqueUnit.NewtonMeter); - TryAdd(table, "N.m", newtonMetre, UNU.TorqueUnit.NewtonMeter); - TryAdd(table, "kNm", kilonewtonMetre, UNU.TorqueUnit.NewtonMeter); - TryAdd(table, "kN.m", kilonewtonMetre, UNU.TorqueUnit.NewtonMeter); - - // Symbols that more than one quantity claims, forced to the reading expected in a building - // engineering context. Left to the loop above, each of these lands on a unit that is never - // the one intended here. The remaining overlaps the loop resolves acceptably on its own: - // "g" to gram, "mg" to milligram, "MN" to meganewton, "kt" to kilotonne, "mil" to mil, - // "m" to metre, "'" to foot and the double prime to inch. - Set(table, "t", UNU.MassUnit.Tonne, UNU.MassUnit.Kilogram); // not Volume.MetricTeaspoon - Set(table, "h", UNU.DurationUnit.Hour, UNU.DurationUnit.Second); // not Length.Hand - Set(table, "min", UNU.DurationUnit.Minute, UNU.DurationUnit.Second); // not Angle.Arcminute - Set(table, "sec", UNU.DurationUnit.Second, UNU.DurationUnit.Second); // not Angle.Arcsecond - - // Units no UnitsNet quantity can express, carried as a plain multiplier to SI instead of a unit. - // A warping constant is the sixth power of a length, and UnitsNet stops at the fourth; section - // tables publish it in dm6 in metric practice and in6 in US practice, so it follows the region - // rather than the length family, which is why all three spellings have to read. - AddFactored(table, "dm⁶", c_DecimetreToTheSixthFactor); - AddFactored(table, "dm6", c_DecimetreToTheSixthFactor); - AddFactored(table, "m⁶", 1.0); - AddFactored(table, "m6", 1.0); - AddFactored(table, "in⁶", m_InchToTheSixthFactor); - AddFactored(table, "in6", m_InchToTheSixthFactor); - - // UnitsNet publishes "%" only as a MassFraction, which BH.oM.Units has no member for. - AddFactored(table, "%", c_PercentFactor); - - return table; - } - - /***************************************************/ - - private static IEnumerable GetAbbreviations(UN.UnitInfo unitInfo) - { - try - { - return UN.UnitsNetSetup.Default.UnitAbbreviations.GetAbbreviations(unitInfo, CultureInfo.InvariantCulture); - } - catch - { - return Array.Empty(); - } - } - - /***************************************************/ - - // Claims a symbol for a unit, leaving any earlier claim on that symbol in place. - private static void TryAdd(Dictionary table, string symbol, - UN.UnitInfo unitInfo, Enum siUnit) - { - if (!string.IsNullOrWhiteSpace(symbol) && !table.ContainsKey(symbol)) - table[symbol] = Spec(unitInfo, siUnit); - } - - /***************************************************/ - - // Claims a symbol for a unit, overriding any earlier claim on that symbol. - private static void Set(Dictionary table, string symbol, Enum unit, Enum siUnit) - { - table[symbol] = Spec(UN.Quantity.GetUnitInfo(unit), siUnit); - } - - /***************************************************/ - - // Claims a symbol for a plain multiplier to SI, leaving any earlier claim on that symbol in place. - private static void AddFactored(Dictionary table, string symbol, double toSIFactor) - { - if (!table.ContainsKey(symbol)) - table[symbol] = new UnitSpec { Factor = toSIFactor }; - } - - /***************************************************/ - - private static UnitSpec Spec(UN.UnitInfo unitInfo, Enum siUnit) - { - return new UnitSpec - { - Unit = unitInfo.Value, - SIUnit = siUnit, - QuantityName = unitInfo.QuantityName - }; - } - - /***************************************************/ - - private static string Ascii(string symbol) - { - return symbol? - .Replace("²", "2") - .Replace("³", "3") - .Replace("⁴", "4") - .Replace("⁶", "6"); - } - - /***************************************************/ - /**** Private Fields ****/ - /***************************************************/ - - // The quantities recognised by ResolveUnit, each represented by the SI unit it converts to and from. - // The unit type of the quantity is taken from the entry itself, so adding a quantity is a single line. - // These are the SI units used by the corresponding BHoM Convert methods, which is not always the UnitsNet - // base unit - notably Temperature, where the BHoM convention is degrees Celsius rather than Kelvin. - // Order matters: where two quantities publish the same unit symbol, the first entry to claim it wins. - // Mass precedes Angle and Acceleration so that "g" resolves to gram rather than gradian or standard gravity. - private static readonly Enum[] m_SIUnits = new Enum[] - { - UNU.LengthUnit.Meter, - UNU.AreaUnit.SquareMeter, - UNU.VolumeUnit.CubicMeter, - UNU.AreaMomentOfInertiaUnit.MeterToTheFourth, - UNU.PressureUnit.Pascal, - UNU.ForceUnit.Newton, - UNU.TorqueUnit.NewtonMeter, - UNU.ForcePerLengthUnit.NewtonPerMeter, - UNU.TorquePerLengthUnit.NewtonMeterPerMeter, - UNU.MassUnit.Kilogram, - UNU.AngleUnit.Radian, - UNU.AccelerationUnit.MeterPerSecondSquared, - UNU.DensityUnit.KilogramPerCubicMeter, - UNU.EnergyUnit.Joule, - UNU.SpeedUnit.MeterPerSecond, - UNU.DurationUnit.Second, - UNU.TemperatureUnit.DegreeCelsius, - UNU.TemperatureDeltaUnit.Kelvin, - UNU.CoefficientOfThermalExpansionUnit.PerKelvin, - UNU.ElectricConductivityUnit.SiemensPerMeter, - UNU.MassFractionUnit.KilogramPerKilogram, - UNU.MolalityUnit.MolePerKilogram, - }; - - private const double c_DecimetreToTheSixthFactor = 1e-6; - private const double c_PercentFactor = 0.01; - - // Taken from LengthUnit.Inch rather than written out, so it cannot drift from the inch the rest of - // the toolkit converts with. - private static readonly double m_InchToTheSixthFactor = 1.0 / Math.Pow(1.0.ToLength(LengthUnit.Inch), 6); - - private static readonly Dictionary m_UnitTable = BuildUnitTable(); - - /***************************************************/ - } -} diff --git a/Units_Engine/Query/UnitSymbol.cs b/Units_Engine/Query/UnitSymbol.cs new file mode 100644 index 0000000..8ed6d09 --- /dev/null +++ b/Units_Engine/Query/UnitSymbol.cs @@ -0,0 +1,127 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes + +using BH.oM.Base.Attributes; +using BH.Engine.Base; + +namespace BH.Engine.Units +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("The engineer-facing symbol for a unit, read from UnitsNet, e.g. LengthUnit.Millimeter " + + "-> \"mm\" and AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\". UnitsNet is the only " + + "thing in the stack that names a unit; a BH.oM.Units member carries no symbol of its own.")] + [Input("unit", "A member of one of the BH.oM.Units unit enums, e.g. LengthUnit.Millimeter.")] + [Output("symbol", "The unit's display symbol, or an empty string for a unit UnitsNet does not know.")] + public static string UnitSymbol(this Enum unit) + { + Type netUnitType; + int netUnitValue; + if (!TryResolveUnitsNetUnit(unit, out netUnitType, out netUnitValue)) + return ""; + + // The list, not GetDefaultAbbreviation: the list comes back empty for a unit UnitsNet has + // registered no symbol for, where the single-value call is only safe once the unit is known to be + // defined. Element 0 is the default abbreviation for every unit UnitsNet publishes. + string[] symbols = UN.UnitsNetSetup.Default.UnitAbbreviations + .GetUnitAbbreviations(netUnitType, netUnitValue, CultureInfo.CurrentCulture); + + if (symbols.Length == 0) + { + Compute.RecordError($"UnitsNet publishes no symbol for {unit}."); + return ""; + } + + return symbols[0]; + } + + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + // The bridge to UnitsNet is by NAME, not value: their integer values disagree for LengthUnit, + // AngleUnit, PressureUnit and others, so a cast would hand back a different unit (Radian -> Revolution). + // Convert.ToBHoMUnit runs the same bridge in the opposite direction. + private static bool TryResolveUnitsNetUnit(Enum unit, out Type netUnitType, out int netUnitValue) + { + netUnitType = null; + netUnitValue = 0; + + if (unit == null) + { + Compute.RecordError("A unit symbol can only be taken from a unit enum member."); + return false; + } + + Type bhomType = unit.GetType(); + + lock (m_UnitsNetTypes) + { + if (!m_UnitsNetTypes.TryGetValue(bhomType, out netUnitType)) + { + netUnitType = bhomType.Namespace == "UnitsNet.Units" + ? bhomType + : typeof(UN.UnitsNetSetup).Assembly.GetType("UnitsNet.Units." + bhomType.Name); + + m_UnitsNetTypes[bhomType] = netUnitType; + } + } + + if (netUnitType == null) + { + Compute.RecordError($"UnitsNet has no {bhomType.Name}, so {unit} has no symbol."); + return false; + } + + string name = unit.ToString(); + if (!Enum.IsDefined(netUnitType, name)) + { + // BH.oM.Units's own Undefined, and anything BHoM has added since, lands here. + Compute.RecordError($"UnitsNet's {netUnitType.Name} has no {name}, so it has no symbol."); + return false; + } + + netUnitValue = System.Convert.ToInt32(Enum.Parse(netUnitType, name)); + return true; + } + + /***************************************************/ + /**** Private Fields ****/ + /***************************************************/ + + // One reflection lookup per unit enum type, not per call. + private static readonly Dictionary m_UnitsNetTypes = new Dictionary(); + + /***************************************************/ + } +} diff --git a/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs b/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs new file mode 100644 index 0000000..690dc4a --- /dev/null +++ b/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs @@ -0,0 +1,43 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BH.oM.Units +{ + // The sixth power of a length, which is what a warping constant is measured in. Member names match + // UnitsNet's WarpingMomentOfInertiaUnit so the by-name bridge to it holds. + public enum WarpingMomentOfInertiaUnit + { + Undefined = 0, + MillimeterToTheSixth = 1, + CentimeterToTheSixth = 2, + DecimeterToTheSixth = 3, + MeterToTheSixth = 4, + InchToTheSixth = 5, + FootToTheSixth = 6 + } +} diff --git a/Units_oM/UnitSpec.cs b/Units_oM/UnitSpec.cs deleted file mode 100644 index bb41499..0000000 --- a/Units_oM/UnitSpec.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using System; -using System.ComponentModel; - -namespace BH.oM.Units -{ - [Description("Specification linking a unit symbol to its unit enumeration value and the SI unit its quantity converts to.")] - public class UnitSpec - { - [Description("The resolved unit. Null for a dimensionless value and for a unit no UnitsNet quantity " + - "can express, in which case Factor is applied instead.")] - public virtual Enum Unit { get; set; } = null; - - [Description("The SI unit that this quantity converts to and from, as defined by the BHoM convention for the quantity.")] - public virtual Enum SIUnit { get; set; } = null; - - [Description("Name of the quantity the unit belongs to, e.g. \"Force\". Empty for a dimensionless value.")] - public virtual string QuantityName { get; set; } = ""; - - [Description("Multiplier taking a value in this unit to SI, read only when Unit is null. 1 for a " + - "dimensionless value; otherwise the conversion for a unit UnitsNet has no quantity for, such as " + - "the sixth power of a length a warping constant is measured in.")] - public virtual double Factor { get; set; } = 1.0; - } -} From 2dd381b6af77d26a94045114d34c6f1ca376c582 Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Tue, 1 Sep 2026 23:52:47 +0100 Subject: [PATCH 07/14] Add warpingmoment unit tetst --- .ci/Datasets/Convert/FromCentimetreToTheSixth.json | 1 + .ci/Datasets/Convert/FromDecimetreToTheSixth.json | 1 + .ci/Datasets/Convert/FromFootToTheSixth.json | 1 + .ci/Datasets/Convert/FromInchToTheSixth.json | 1 + .ci/Datasets/Convert/FromMillimetreToTheSixth.json | 1 + .ci/Datasets/Convert/ToCentimetreToTheSixth.json | 1 + .ci/Datasets/Convert/ToDecimetreToTheSixth.json | 1 + .ci/Datasets/Convert/ToFootToTheSixth.json | 1 + .ci/Datasets/Convert/ToInchToTheSixth.json | 1 + .ci/Datasets/Convert/ToMillimetreToTheSixth.json | 1 + 10 files changed, 10 insertions(+) create mode 100644 .ci/Datasets/Convert/FromCentimetreToTheSixth.json create mode 100644 .ci/Datasets/Convert/FromDecimetreToTheSixth.json create mode 100644 .ci/Datasets/Convert/FromFootToTheSixth.json create mode 100644 .ci/Datasets/Convert/FromInchToTheSixth.json create mode 100644 .ci/Datasets/Convert/FromMillimetreToTheSixth.json create mode 100644 .ci/Datasets/Convert/ToCentimetreToTheSixth.json create mode 100644 .ci/Datasets/Convert/ToDecimetreToTheSixth.json create mode 100644 .ci/Datasets/Convert/ToFootToTheSixth.json create mode 100644 .ci/Datasets/Convert/ToInchToTheSixth.json create mode 100644 .ci/Datasets/Convert/ToMillimetreToTheSixth.json diff --git a/.ci/Datasets/Convert/FromCentimetreToTheSixth.json b/.ci/Datasets/Convert/FromCentimetreToTheSixth.json new file mode 100644 index 0000000..cae1bc1 --- /dev/null +++ b/.ci/Datasets/Convert/FromCentimetreToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "FromCentimetreToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "a56231ed-244c-4fa0-9b66-95ea77b951a3", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "FromCentimetreToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [9.9999999999999998E-13], "BHoM_Guid" : "b949d662-bcd9-44cf-bc0c-4c30e3134da4", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000.0], "Outputs" : [1.0000000000000001E-09], "BHoM_Guid" : "a1887f9f-ecc3-41ed-a501-3118fb45eeaa", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [100000.0], "Outputs" : [9.9999999999999995E-08], "BHoM_Guid" : "7e643c95-aee1-40f0-9446-75284817bb7a", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000000000000.0], "Outputs" : [1.0], "BHoM_Guid" : "9a153609-4920-4352-9265-b57652840b36", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-1000.0], "Outputs" : [-1.0000000000000001E-09], "BHoM_Guid" : "61781c46-7e55-44e7-aa4b-073136dcf43b", "Name" : "" }], "BHoM_Guid" : "40dd9c69-03e5-487a-9658-be91020db34c", "Name" : "" }], "BHoM_Guid" : "c8b775d3-5ddb-487f-8961-83b36cd98d21", "Name" : "FromCentimetreToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/FromDecimetreToTheSixth.json b/.ci/Datasets/Convert/FromDecimetreToTheSixth.json new file mode 100644 index 0000000..976ddfb --- /dev/null +++ b/.ci/Datasets/Convert/FromDecimetreToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "FromDecimetreToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "6d9b560f-5cea-4da9-b9b6-fc6570f51444", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "FromDecimetreToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [9.9999999999999995E-07], "BHoM_Guid" : "74e0112a-a94d-4fc7-a67f-89568ca8a26b", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [100.0], "Outputs" : [0.0001], "BHoM_Guid" : "0b506374-99f0-4141-9d67-a24f3f812150", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000.0], "Outputs" : [0.01], "BHoM_Guid" : "ca50840a-d8ab-4354-9f16-c85d83bc1fe7", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.001], "Outputs" : [1.0000000000000001E-09], "BHoM_Guid" : "1a221cc0-7459-43f8-baf2-28a0f030ec80", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-100.0], "Outputs" : [-0.0001], "BHoM_Guid" : "93821ae5-caa0-4931-abae-537c81e500d8", "Name" : "" }], "BHoM_Guid" : "d86f9290-7ea9-41f8-ac37-829cba72d5b0", "Name" : "" }], "BHoM_Guid" : "d916efbe-9458-47d5-9771-a19c936e28f9", "Name" : "FromDecimetreToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/FromFootToTheSixth.json b/.ci/Datasets/Convert/FromFootToTheSixth.json new file mode 100644 index 0000000..ce7b3a6 --- /dev/null +++ b/.ci/Datasets/Convert/FromFootToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "FromFootToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "891dcac5-79d7-4e74-a591-9d78faead07d", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "FromFootToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [0.00080184380091486221], "BHoM_Guid" : "17ed4022-3bbf-40e8-98f0-e1b95eca2a97", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000.0], "Outputs" : [0.80184380091486218], "BHoM_Guid" : "b2bf42f8-d757-4f71-ab15-a8543434c820", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [100000.0], "Outputs" : [80.184380091486219], "BHoM_Guid" : "4bf5fd81-ff09-4bfc-b368-2792762c344d", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.10000000000000001], "Outputs" : [8.0184380091486229E-05], "BHoM_Guid" : "a536a448-85df-42e8-b74e-70ec0c96a7aa", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-1000.0], "Outputs" : [-0.80184380091486218], "BHoM_Guid" : "4798f5b4-21b4-4102-ab6c-4bbed54dd416", "Name" : "" }], "BHoM_Guid" : "5b2ab526-c7c8-4329-884c-86329e5aa8f4", "Name" : "" }], "BHoM_Guid" : "64afa94c-003e-4f1f-89e9-9d399bcc9692", "Name" : "FromFootToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/FromInchToTheSixth.json b/.ci/Datasets/Convert/FromInchToTheSixth.json new file mode 100644 index 0000000..147d0a0 --- /dev/null +++ b/.ci/Datasets/Convert/FromInchToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "FromInchToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "d90ae17d-3c31-45e2-8055-b750299fcc15", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "FromInchToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [2.6853586654009591E-10], "BHoM_Guid" : "6725685c-8e01-4c98-9ab1-361d0549a4f8", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000.0], "Outputs" : [2.6853586654009593E-07], "BHoM_Guid" : "c3d7e609-1a3a-4fc0-9ac0-7395e88df4ad", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000.0], "Outputs" : [2.6853586654009592E-06], "BHoM_Guid" : "857a7817-23a7-40b1-bc2f-089146cc70fa", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.10000000000000001], "Outputs" : [2.6853586654009594E-11], "BHoM_Guid" : "71655be3-bfe5-446b-b201-ee61d802f9c6", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-1000.0], "Outputs" : [-2.6853586654009593E-07], "BHoM_Guid" : "118eb0a9-0b57-4bcb-94e8-f9ca2cdae33f", "Name" : "" }], "BHoM_Guid" : "18ea5659-8326-4af0-b2ad-5f0a8acddf4d", "Name" : "" }], "BHoM_Guid" : "2583bed8-b48d-4423-a089-68ff6a1979ee", "Name" : "FromInchToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/FromMillimetreToTheSixth.json b/.ci/Datasets/Convert/FromMillimetreToTheSixth.json new file mode 100644 index 0000000..9dd9916 --- /dev/null +++ b/.ci/Datasets/Convert/FromMillimetreToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "FromMillimetreToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "9c5c7c64-4bac-40ab-960e-d7489afd6f08", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "FromMillimetreToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.0], "Outputs" : [0.0], "BHoM_Guid" : "b3e252ec-4dcd-490c-9866-def89f733688", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000000.0], "Outputs" : [9.9999999999999994E-12], "BHoM_Guid" : "978d72f1-7708-45ff-9570-b48ecb05c80b", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000000000.0], "Outputs" : [1.0000000000000001E-09], "BHoM_Guid" : "7d60a234-fee6-44f4-aedc-3eda0bf032df", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000000000.0], "Outputs" : [1E-08], "BHoM_Guid" : "b4670630-ea26-4f6b-b50c-d119ea5b9243", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-100000000.0], "Outputs" : [-1E-10], "BHoM_Guid" : "91656cb8-16be-4935-9de8-6457abc85c9a", "Name" : "" }], "BHoM_Guid" : "de1fc349-206d-47b2-9fb0-c26e4b9ffc64", "Name" : "" }], "BHoM_Guid" : "267467fb-aba3-47aa-8057-29caf166e661", "Name" : "FromMillimetreToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/ToCentimetreToTheSixth.json b/.ci/Datasets/Convert/ToCentimetreToTheSixth.json new file mode 100644 index 0000000..22fb6bd --- /dev/null +++ b/.ci/Datasets/Convert/ToCentimetreToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "ToCentimetreToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "94b48765-b156-4af8-8df1-678f92115fc6", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "ToCentimetreToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [1000000000000.0], "BHoM_Guid" : "08a3bbe8-36b4-4dff-840b-ac896a07f687", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000.0], "Outputs" : [1000000000000000.0], "BHoM_Guid" : "1c520646-79aa-4116-a362-c0b7c48fdeb4", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [100000.0], "Outputs" : [1E+17], "BHoM_Guid" : "974a8a79-23a7-417d-8d60-de3da3ffe2f2", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000000000000.0], "Outputs" : [9.9999999999999998E+23], "BHoM_Guid" : "51e5d1bc-847c-471e-b564-8418ce8a6304", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-1000.0], "Outputs" : [-1000000000000000.0], "BHoM_Guid" : "224ef19e-4854-4232-88c3-c4df33dd48e2", "Name" : "" }], "BHoM_Guid" : "cfeb9474-a223-47c1-b7a4-ef081d0fb671", "Name" : "" }], "BHoM_Guid" : "d7d7c26f-1ba2-4e93-b507-d7ebb0ff0c97", "Name" : "ToCentimetreToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/ToDecimetreToTheSixth.json b/.ci/Datasets/Convert/ToDecimetreToTheSixth.json new file mode 100644 index 0000000..c882425 --- /dev/null +++ b/.ci/Datasets/Convert/ToDecimetreToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "ToDecimetreToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "38396e9d-92dd-4fa4-b010-913d0ea5f473", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "ToDecimetreToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [1000000.0], "BHoM_Guid" : "86505fb1-0576-4429-ab5e-0c62c75f1bff", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [100.0], "Outputs" : [100000000.0], "BHoM_Guid" : "fb068190-1459-4881-88fd-bcdd8eb8d688", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000.0], "Outputs" : [10000000000.0], "BHoM_Guid" : "76abaa87-536e-4a79-8e2e-55d5ae1e72c1", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.001], "Outputs" : [1000.0], "BHoM_Guid" : "ac18d38e-fb3d-4ed2-9e43-d298b4a0c153", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-100.0], "Outputs" : [-100000000.0], "BHoM_Guid" : "eb10a543-d1be-44fe-a066-d6c13c52f652", "Name" : "" }], "BHoM_Guid" : "fcf0042d-dfa0-468b-acc9-0e7b215651d8", "Name" : "" }], "BHoM_Guid" : "3cfeffdd-d84c-4b3f-aa7d-3d603b061e40", "Name" : "ToDecimetreToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/ToFootToTheSixth.json b/.ci/Datasets/Convert/ToFootToTheSixth.json new file mode 100644 index 0000000..d6251d5 --- /dev/null +++ b/.ci/Datasets/Convert/ToFootToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "ToFootToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "5a594d16-76d9-4d0d-adab-4bb454e9d822", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "ToFootToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [1247.1256856498135], "BHoM_Guid" : "92fa0e18-4e05-4557-b924-df1f8048db1d", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000.0], "Outputs" : [1247125.6856498134], "BHoM_Guid" : "6e65be3e-26f9-4bad-8e63-cdec966ed351", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [100000.0], "Outputs" : [124712568.56498134], "BHoM_Guid" : "f1075484-e582-4209-a035-66272ba54dff", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.10000000000000001], "Outputs" : [124.71256856498134], "BHoM_Guid" : "36f5ae10-b9d3-4804-afa8-241ade3f3814", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-1000.0], "Outputs" : [-1247125.6856498134], "BHoM_Guid" : "e42c2050-f5d5-4d61-adb6-b78b9bec7b6a", "Name" : "" }], "BHoM_Guid" : "94a87a27-e72a-4734-8e9a-9dcd352c3904", "Name" : "" }], "BHoM_Guid" : "c5c816e5-91cd-429a-9bea-2f8e1f60ef35", "Name" : "ToFootToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/ToInchToTheSixth.json b/.ci/Datasets/Convert/ToInchToTheSixth.json new file mode 100644 index 0000000..c6e5561 --- /dev/null +++ b/.ci/Datasets/Convert/ToInchToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "ToInchToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "ee0fefdb-e16f-455e-9142-cdb05cbe7b1b", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "ToInchToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1.0], "Outputs" : [3723897343.3393745], "BHoM_Guid" : "359104e3-ffec-4a2c-9be6-c6e12ac41786", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000.0], "Outputs" : [3723897343339.3745], "BHoM_Guid" : "409a5f68-32d4-4e2c-bd27-afa66a15ec21", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000.0], "Outputs" : [37238973433393.742], "BHoM_Guid" : "c6c72b7d-6bda-4b81-b008-0a1cf3ecbdc6", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.10000000000000001], "Outputs" : [372389734.33393747], "BHoM_Guid" : "8fb05b53-4ace-4282-b2f4-470a16d39560", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-1000.0], "Outputs" : [-3723897343339.3745], "BHoM_Guid" : "becb52dd-e5e4-42c9-ae8c-99c9a889fb7e", "Name" : "" }], "BHoM_Guid" : "7c229b38-52b3-43e4-a479-53c87cac5f2a", "Name" : "" }], "BHoM_Guid" : "186dc5b2-ebbc-4019-a904-f9bf23cc4a01", "Name" : "ToInchToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file diff --git a/.ci/Datasets/Convert/ToMillimetreToTheSixth.json b/.ci/Datasets/Convert/ToMillimetreToTheSixth.json new file mode 100644 index 0000000..1d2cfe3 --- /dev/null +++ b/.ci/Datasets/Convert/ToMillimetreToTheSixth.json @@ -0,0 +1 @@ +{ "_t" : "BH.oM.Data.Library.Dataset", "SourceInformation" : { "_t" : "BH.oM.Data.Library.Source", "SourceLink" : "", "Title" : "ToMillimetreToTheSixth", "Author" : "Christopher Short", "ItemReference" : "", "Version" : "", "Publisher" : "", "Schema" : "", "Language" : "", "Location" : "", "Copyright" : "", "Contributors" : "", "Confidence" : "High", "BHoM_Guid" : "01947f4e-1404-46de-92ca-a8ba5683e6ec", "Name" : "" }, "TimeOfCreation" : { "$date" : 1788302930950 }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.UnitTest", "Method" : { "_t" : "System.Reflection.MethodBase", "TypeName" : "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Engine.Units.Convert, Units_Engine, Version=9.0.0.0, Culture=neutral, PublicKeyToken=null\", \"_bhomVersion\" : \"9.3\" }", "MethodName" : "ToMillimetreToTheSixth", "Parameters" : ["{ \"_t\" : \"System.Type\", \"Name\" : \"System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\", \"_bhomVersion\" : \"9.3\" }"], "_bhomVersion" : "9.3" }, "Data" : [{ "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [0.0], "Outputs" : [0.0], "BHoM_Guid" : "b9211dbd-c5b5-422f-b278-c190650d0f2b", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000000.0], "Outputs" : [1.0000000000000001E+25], "BHoM_Guid" : "a653e8a9-c0df-442a-bac9-6d109e7dcfdd", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [1000000000.0], "Outputs" : [1E+27], "BHoM_Guid" : "1f6757b8-4975-447a-a620-d470eb7bd577", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [10000000000.0], "Outputs" : [9.9999999999999996E+27], "BHoM_Guid" : "b10535ce-6733-4968-9b65-9a1f80eed377", "Name" : "" }, { "_t" : "BH.oM.Test.UnitTests.TestData", "Inputs" : [-100000000.0], "Outputs" : [-1E+26], "BHoM_Guid" : "035f3ad8-2bea-4386-886f-2e041c704be9", "Name" : "" }], "BHoM_Guid" : "e16c0c1b-422e-4355-b3ae-d96c3a693234", "Name" : "" }], "BHoM_Guid" : "8be92390-1511-400b-ba17-5aeb8d6211ff", "Name" : "ToMillimetreToTheSixth", "_bhomVersion" : "9.3" } \ No newline at end of file From e4687979e95d7cb48f6fd9f44f54fd7468cb928e Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Wed, 2 Sep 2026 14:09:02 +0100 Subject: [PATCH 08/14] Update punctuation CI check --- .../WarpingMomentOfInertia/CentimetreToTheSixth.cs | 10 +++++----- .../WarpingMomentOfInertia/DecimetreToTheSixth.cs | 12 ++++++------ .../Convert/WarpingMomentOfInertia/FootToTheSixth.cs | 12 ++++++------ .../Convert/WarpingMomentOfInertia/InchToTheSixth.cs | 12 ++++++------ .../WarpingMomentOfInertia/MillimetreToTheSixth.cs | 12 ++++++------ 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs index d678eca..e76bac2 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs @@ -37,17 +37,17 @@ namespace BH.Engine.Units { public static partial class Convert { - [Description("Convert SI units (metres to the sixth) into centimetres to the sixth")] - [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] - [Output("centimetresToTheSixth", "The number of centimetres to the sixth")] + [Description("Convert SI units (metres to the sixth) into centimetres to the sixth.")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert.", typeof(WarpingMomentOfInertiaUnit))] + [Output("centimetresToTheSixth", "The number of centimetres to the sixth.")] public static double ToCentimetreToTheSixth(this double metresToTheSixth) { UN.QuantityValue qv = metresToTheSixth; return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.CentimeterToTheSixth); } - [Description("Convert centimetres to the sixth into SI units (metres to the sixth)")] - [Input("centimetresToTheSixth", "The number of centimetres to the sixth to convert")] + [Description("Convert centimetres to the sixth into SI units (metres to the sixth).")] + [Input("centimetresToTheSixth", "The number of centimetres to the sixth to convert.")] [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] public static double FromCentimetreToTheSixth(this double centimetresToTheSixth) { diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs index 98b1922..18e5d95 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/DecimetreToTheSixth.cs @@ -37,18 +37,18 @@ namespace BH.Engine.Units { public static partial class Convert { - [Description("Convert SI units (metres to the sixth) into decimetres to the sixth")] - [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] - [Output("decimetresToTheSixth", "The number of decimetres to the sixth")] + [Description("Convert SI units (metres to the sixth) into decimetres to the sixth.")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert.", typeof(WarpingMomentOfInertiaUnit))] + [Output("decimetresToTheSixth", "The number of decimetres to the sixth.")] public static double ToDecimetreToTheSixth(this double metresToTheSixth) { UN.QuantityValue qv = metresToTheSixth; return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.DecimeterToTheSixth); } - [Description("Convert decimetres to the sixth into SI units (metres to the sixth)")] - [Input("decimetresToTheSixth", "The number of decimetres to the sixth to convert")] - [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + [Description("Convert decimetres to the sixth into SI units (metres to the sixth).")] + [Input("decimetresToTheSixth", "The number of decimetres to the sixth to convert.")] + [Output("metresToTheSixth", "The number of metres to the sixth.", typeof(WarpingMomentOfInertiaUnit))] public static double FromDecimetreToTheSixth(this double decimetresToTheSixth) { UN.QuantityValue qv = decimetresToTheSixth; diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs index 7e0a2f5..315196b 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/FootToTheSixth.cs @@ -37,18 +37,18 @@ namespace BH.Engine.Units { public static partial class Convert { - [Description("Convert SI units (metres to the sixth) into feet to the sixth")] - [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] - [Output("feetToTheSixth", "The number of feet to the sixth")] + [Description("Convert SI units (metres to the sixth) into feet to the sixth.")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert.", typeof(WarpingMomentOfInertiaUnit))] + [Output("feetToTheSixth", "The number of feet to the sixth.")] public static double ToFootToTheSixth(this double metresToTheSixth) { UN.QuantityValue qv = metresToTheSixth; return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.FootToTheSixth); } - [Description("Convert feet to the sixth into SI units (metres to the sixth)")] - [Input("feetToTheSixth", "The number of feet to the sixth to convert")] - [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + [Description("Convert feet to the sixth into SI units (metres to the sixth).")] + [Input("feetToTheSixth", "The number of feet to the sixth to convert.")] + [Output("metresToTheSixth", "The number of metres to the sixth.", typeof(WarpingMomentOfInertiaUnit))] public static double FromFootToTheSixth(this double feetToTheSixth) { UN.QuantityValue qv = feetToTheSixth; diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs index bc15820..eaf3712 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/InchToTheSixth.cs @@ -37,18 +37,18 @@ namespace BH.Engine.Units { public static partial class Convert { - [Description("Convert SI units (metres to the sixth) into inches to the sixth")] - [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] - [Output("inchesToTheSixth", "The number of inches to the sixth")] + [Description("Convert SI units (metres to the sixth) into inches to the sixth.")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert.", typeof(WarpingMomentOfInertiaUnit))] + [Output("inchesToTheSixth", "The number of inches to the sixth.")] public static double ToInchToTheSixth(this double metresToTheSixth) { UN.QuantityValue qv = metresToTheSixth; return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.InchToTheSixth); } - [Description("Convert inches to the sixth into SI units (metres to the sixth)")] - [Input("inchesToTheSixth", "The number of inches to the sixth to convert")] - [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + [Description("Convert inches to the sixth into SI units (metres to the sixth).")] + [Input("inchesToTheSixth", "The number of inches to the sixth to convert.")] + [Output("metresToTheSixth", "The number of metres to the sixth.", typeof(WarpingMomentOfInertiaUnit))] public static double FromInchToTheSixth(this double inchesToTheSixth) { UN.QuantityValue qv = inchesToTheSixth; diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs index 81f6eb0..1da4a3f 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/MillimetreToTheSixth.cs @@ -37,18 +37,18 @@ namespace BH.Engine.Units { public static partial class Convert { - [Description("Convert SI units (metres to the sixth) into millimetres to the sixth")] - [Input("metresToTheSixth", "The number of metres to the sixth to convert", typeof(WarpingMomentOfInertiaUnit))] - [Output("millimetresToTheSixth", "The number of millimetres to the sixth")] + [Description("Convert SI units (metres to the sixth) into millimetres to the sixth.")] + [Input("metresToTheSixth", "The number of metres to the sixth to convert.", typeof(WarpingMomentOfInertiaUnit))] + [Output("millimetresToTheSixth", "The number of millimetres to the sixth.")] public static double ToMillimetreToTheSixth(this double metresToTheSixth) { UN.QuantityValue qv = metresToTheSixth; return UN.UnitConverter.Convert(qv, WarpingMomentOfInertiaUnit.MeterToTheSixth, WarpingMomentOfInertiaUnit.MillimeterToTheSixth); } - [Description("Convert millimetres to the sixth into SI units (metres to the sixth)")] - [Input("millimetresToTheSixth", "The number of millimetres to the sixth to convert")] - [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + [Description("Convert millimetres to the sixth into SI units (metres to the sixth).")] + [Input("millimetresToTheSixth", "The number of millimetres to the sixth to convert.")] + [Output("metresToTheSixth", "The number of metres to the sixth.", typeof(WarpingMomentOfInertiaUnit))] public static double FromMillimetreToTheSixth(this double millimetresToTheSixth) { UN.QuantityValue qv = millimetresToTheSixth; From 2ad7410671382a9451a1c5834f600e03961fd7ae Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Wed, 2 Sep 2026 15:33:23 +0100 Subject: [PATCH 09/14] Respond to comments --- Units_Engine/Convert/FromUnit.cs | 130 +++++-------------- Units_Engine/Convert/ToUnit.cs | 60 ++++----- Units_oM/Enums/WarpingMomentOfInertiaUnit.cs | 2 - 3 files changed, 57 insertions(+), 135 deletions(-) diff --git a/Units_Engine/Convert/FromUnit.cs b/Units_Engine/Convert/FromUnit.cs index fc6d87f..a7cd0e1 100644 --- a/Units_Engine/Convert/FromUnit.cs +++ b/Units_Engine/Convert/FromUnit.cs @@ -40,123 +40,51 @@ public static partial class Convert "The inverse of ToUnit.")] [Input("value", "The value in the given unit.")] [Input("unit", "The unit the value is in, as a member of one of the BH.oM.Units unit enums, e.g. " + - "LengthUnit.Millimeter. A UnitsNet unit is read as well, but records a warning.")] + "LengthUnit.Millimeter.")] [Output("siValue", "The value in SI units, or NaN when the unit has no conversion.")] public static double FromUnit(this double value, Enum unit) { // No unit is how a dimensionless quantity arrives - a Ratio or a Strain. Nothing to convert, // so the value passes straight through. if (unit == null) + { + Compute.RecordError($"BH.Engine.Units has no conversion for a null unit."); return value; - - Enum bhomUnit = BHoMUnit(unit); - if (bhomUnit == null) - return double.NaN; + } // The unit's type names its quantity, so the type is the whole of the dispatch. This is why the // unit travels as an enum and not as a symbol: a symbol two quantities both publish - "t" for // both a tonne and a teaspoon - would have to be guessed at, where a type cannot be mistaken. - switch (bhomUnit.GetType().Name) + switch (unit.GetType().Name) { - case nameof(LengthUnit): return value.FromLength(bhomUnit); - case nameof(AreaUnit): return value.FromArea(bhomUnit); - case nameof(VolumeUnit): return value.FromVolume(bhomUnit); - case nameof(AreaMomentOfInertiaUnit): return value.FromAreaMomentOfInertia(bhomUnit); - case nameof(PressureUnit): return value.FromPressure(bhomUnit); - case nameof(ForceUnit): return value.FromForce(bhomUnit); - case nameof(TorqueUnit): return value.FromTorque(bhomUnit); - case nameof(ForcePerLengthUnit): return value.FromForcePerLength(bhomUnit); - case nameof(TorquePerLengthUnit): return value.FromMomentPerLength(bhomUnit); - case nameof(MassUnit): return value.FromMass(bhomUnit); - case nameof(AngleUnit): return value.FromAngle(bhomUnit); - case nameof(AccelerationUnit): return value.FromAcceleration(bhomUnit); - case nameof(DensityUnit): return value.FromDensity(bhomUnit); - case nameof(EnergyUnit): return value.FromEnergy(bhomUnit); - case nameof(SpeedUnit): return value.FromSpeed(bhomUnit); - case nameof(DurationUnit): return value.FromDuration(bhomUnit); - case nameof(TemperatureUnit): return value.FromTemperature(bhomUnit); - case nameof(TemperatureDeltaUnit): return value.FromTemperatureDelta(bhomUnit); - case nameof(CoefficientOfThermalExpansionUnit): return value.FromCoefficientOfThermalExpansion(bhomUnit); - case nameof(ElectricConductivityUnit): return value.FromElectricConductivity(bhomUnit); - case nameof(MassFractionUnit): return value.FromMassFraction(bhomUnit); - case nameof(MolalityUnit): return value.FromMolality(bhomUnit); - case nameof(WarpingMomentOfInertiaUnit): return value.FromWarpingMomentOfInertia(bhomUnit); + case nameof(LengthUnit): return value.FromLength(unit); + case nameof(AreaUnit): return value.FromArea(unit); + case nameof(VolumeUnit): return value.FromVolume(unit); + case nameof(AreaMomentOfInertiaUnit): return value.FromAreaMomentOfInertia(unit); + case nameof(PressureUnit): return value.FromPressure(unit); + case nameof(ForceUnit): return value.FromForce(unit); + case nameof(TorqueUnit): return value.FromTorque(unit); + case nameof(ForcePerLengthUnit): return value.FromForcePerLength(unit); + case nameof(TorquePerLengthUnit): return value.FromMomentPerLength(unit); + case nameof(MassUnit): return value.FromMass(unit); + case nameof(AngleUnit): return value.FromAngle(unit); + case nameof(AccelerationUnit): return value.FromAcceleration(unit); + case nameof(DensityUnit): return value.FromDensity(unit); + case nameof(EnergyUnit): return value.FromEnergy(unit); + case nameof(SpeedUnit): return value.FromSpeed(unit); + case nameof(DurationUnit): return value.FromDuration(unit); + case nameof(TemperatureUnit): return value.FromTemperature(unit); + case nameof(TemperatureDeltaUnit): return value.FromTemperatureDelta(unit); + case nameof(CoefficientOfThermalExpansionUnit): return value.FromCoefficientOfThermalExpansion(unit); + case nameof(ElectricConductivityUnit): return value.FromElectricConductivity(unit); + case nameof(MassFractionUnit): return value.FromMassFraction(unit); + case nameof(MolalityUnit): return value.FromMolality(unit); + case nameof(WarpingMomentOfInertiaUnit): return value.FromWarpingMomentOfInertia(unit); default: - Compute.RecordError($"BH.Engine.Units has no conversion for a {bhomUnit.GetType().Name}."); + Compute.RecordError($"BH.Engine.Units has no conversion for a {unit.GetType().Name}."); return double.NaN; } } - - /***************************************************/ - /**** Private Methods ****/ - /***************************************************/ - - // Shared by both FromUnit and ToUnit overloads. BH.oM.Units.ForceUnit and UnitsNet.Units.ForceUnit - // share a Type.Name, so this has to run before the switch: a UnitsNet unit would otherwise match its - // case and then come back NaN from FromForce, which reads only BHoM units. - private static Enum BHoMUnit(Enum unit) - { - Enum bhomUnit = unit.GetType().Namespace == "BH.oM.Units" ? unit : ToBHoMUnit(unit); - if (bhomUnit == null) - return null; - - // Every BH.oM.Units enum carries one, and it names no unit. - if (bhomUnit.ToString() == "Undefined") - { - Compute.RecordError($"{bhomUnit.GetType().Name}.Undefined names no unit, so there is nothing to convert to."); - return null; - } - - return bhomUnit; - } - - /***************************************************/ - - // The bridge is by NAME, not value: the two enums' integer values disagree - BH.oM.Units.LengthUnit - // .Meter is 18 where UnitsNet's is 21 - so a cast would hand back a different unit entirely. - private static Enum ToBHoMUnit(Enum unit) - { - Type type = unit.GetType(); - - Compute.RecordWarning($"{type.FullName} is not a BHoM unit. Use BH.oM.Units.{type.Name}.{unit} " + - "instead - BH.Engine.Units converts BHoM units, and reads any other unit enum as a fallback only."); - - Type bhomType; - lock (m_BHoMUnitTypes) - { - if (!m_BHoMUnitTypes.TryGetValue(type, out bhomType)) - { - bhomType = typeof(LengthUnit).Assembly.GetType("BH.oM.Units." + type.Name); - m_BHoMUnitTypes[type] = bhomType; - } - } - - if (bhomType == null) - { - Compute.RecordError($"BH.oM.Units has no {type.Name}, so {unit} cannot be converted."); - return null; - } - - string name = unit.ToString(); - if (!Enum.IsDefined(bhomType, name)) - { - Compute.RecordError($"BH.oM.Units.{type.Name} has no {name}, so it cannot be converted."); - return null; - } - - return (Enum)Enum.Parse(bhomType, name); - } - - /***************************************************/ - - /***************************************************/ - /**** Private Fields ****/ - /***************************************************/ - - // One reflection lookup per foreign unit enum type, not per call. - private static readonly Dictionary m_BHoMUnitTypes = new Dictionary(); - - /***************************************************/ } } diff --git a/Units_Engine/Convert/ToUnit.cs b/Units_Engine/Convert/ToUnit.cs index adb5307..aaec08a 100644 --- a/Units_Engine/Convert/ToUnit.cs +++ b/Units_Engine/Convert/ToUnit.cs @@ -46,43 +46,39 @@ public static double ToUnit(this double siValue, Enum unit) // No unit is how a dimensionless quantity arrives - a Ratio or a Strain. Nothing to convert, // so the value passes straight through. if (unit == null) + { + Compute.RecordError($"BH.Engine.Units has no conversion for a null unit."); return siValue; + } - Enum bhomUnit = BHoMUnit(unit); - if (bhomUnit == null) - return double.NaN; - - // The unit's type names its quantity, so the type is the whole of the dispatch. This is why the - // unit travels as an enum and not as a symbol: a symbol two quantities both publish - "t" for - // both a tonne and a teaspoon - would have to be guessed at, where a type cannot be mistaken. - switch (bhomUnit.GetType().Name) + switch (unit.GetType().Name) { - case nameof(LengthUnit): return siValue.ToLength(bhomUnit); - case nameof(AreaUnit): return siValue.ToArea(bhomUnit); - case nameof(VolumeUnit): return siValue.ToVolume(bhomUnit); - case nameof(AreaMomentOfInertiaUnit): return siValue.ToAreaMomentOfInertia(bhomUnit); - case nameof(PressureUnit): return siValue.ToPressure(bhomUnit); - case nameof(ForceUnit): return siValue.ToForce(bhomUnit); - case nameof(TorqueUnit): return siValue.ToTorque(bhomUnit); - case nameof(ForcePerLengthUnit): return siValue.ToForcePerLength(bhomUnit); - case nameof(TorquePerLengthUnit): return siValue.ToMomentPerLength(bhomUnit); - case nameof(MassUnit): return siValue.ToMass(bhomUnit); - case nameof(AngleUnit): return siValue.ToAngle(bhomUnit); - case nameof(AccelerationUnit): return siValue.ToAcceleration(bhomUnit); - case nameof(DensityUnit): return siValue.ToDensity(bhomUnit); - case nameof(EnergyUnit): return siValue.ToEnergy(bhomUnit); - case nameof(SpeedUnit): return siValue.ToSpeed(bhomUnit); - case nameof(DurationUnit): return siValue.ToDuration(bhomUnit); - case nameof(TemperatureUnit): return siValue.ToTemperature(bhomUnit); - case nameof(TemperatureDeltaUnit): return siValue.ToTemperatureDelta(bhomUnit); - case nameof(CoefficientOfThermalExpansionUnit): return siValue.ToCoefficientOfThermalExpansion(bhomUnit); - case nameof(ElectricConductivityUnit): return siValue.ToElectricConductivity(bhomUnit); - case nameof(MassFractionUnit): return siValue.ToMassFraction(bhomUnit); - case nameof(MolalityUnit): return siValue.ToMolality(bhomUnit); - case nameof(WarpingMomentOfInertiaUnit): return siValue.ToWarpingMomentOfInertia(bhomUnit); + case nameof(LengthUnit): return siValue.ToLength(unit); + case nameof(AreaUnit): return siValue.ToArea(unit); + case nameof(VolumeUnit): return siValue.ToVolume(unit); + case nameof(AreaMomentOfInertiaUnit): return siValue.ToAreaMomentOfInertia(unit); + case nameof(PressureUnit): return siValue.ToPressure(unit); + case nameof(ForceUnit): return siValue.ToForce(unit); + case nameof(TorqueUnit): return siValue.ToTorque(unit); + case nameof(ForcePerLengthUnit): return siValue.ToForcePerLength(unit); + case nameof(TorquePerLengthUnit): return siValue.ToMomentPerLength(unit); + case nameof(MassUnit): return siValue.ToMass(unit); + case nameof(AngleUnit): return siValue.ToAngle(unit); + case nameof(AccelerationUnit): return siValue.ToAcceleration(unit); + case nameof(DensityUnit): return siValue.ToDensity(unit); + case nameof(EnergyUnit): return siValue.ToEnergy(unit); + case nameof(SpeedUnit): return siValue.ToSpeed(unit); + case nameof(DurationUnit): return siValue.ToDuration(unit); + case nameof(TemperatureUnit): return siValue.ToTemperature(unit); + case nameof(TemperatureDeltaUnit): return siValue.ToTemperatureDelta(unit); + case nameof(CoefficientOfThermalExpansionUnit): return siValue.ToCoefficientOfThermalExpansion(unit); + case nameof(ElectricConductivityUnit): return siValue.ToElectricConductivity(unit); + case nameof(MassFractionUnit): return siValue.ToMassFraction(unit); + case nameof(MolalityUnit): return siValue.ToMolality(unit); + case nameof(WarpingMomentOfInertiaUnit): return siValue.ToWarpingMomentOfInertia(unit); default: - Compute.RecordError($"BH.Engine.Units has no conversion for a {bhomUnit.GetType().Name}."); + Compute.RecordError($"BH.Engine.Units has no conversion for a {unit.GetType().Name}."); return double.NaN; } } diff --git a/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs b/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs index 690dc4a..4a5772a 100644 --- a/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs +++ b/Units_oM/Enums/WarpingMomentOfInertiaUnit.cs @@ -28,8 +28,6 @@ namespace BH.oM.Units { - // The sixth power of a length, which is what a warping constant is measured in. Member names match - // UnitsNet's WarpingMomentOfInertiaUnit so the by-name bridge to it holds. public enum WarpingMomentOfInertiaUnit { Undefined = 0, From f65e6ba221bd093375223393d80f1ee3889365c0 Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Thu, 3 Sep 2026 13:05:11 +0100 Subject: [PATCH 10/14] Complete PR --- .../CentimetreToTheSixth.cs | 2 +- Units_Engine/Query/UnitSymbol.cs | 127 ------------------ 2 files changed, 1 insertion(+), 128 deletions(-) delete mode 100644 Units_Engine/Query/UnitSymbol.cs diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs b/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs index e76bac2..970b547 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/CentimetreToTheSixth.cs @@ -48,7 +48,7 @@ public static double ToCentimetreToTheSixth(this double metresToTheSixth) [Description("Convert centimetres to the sixth into SI units (metres to the sixth).")] [Input("centimetresToTheSixth", "The number of centimetres to the sixth to convert.")] - [Output("metresToTheSixth", "The number of metres to the sixth", typeof(WarpingMomentOfInertiaUnit))] + [Output("metresToTheSixth", "The number of metres to the sixth.", typeof(WarpingMomentOfInertiaUnit))] public static double FromCentimetreToTheSixth(this double centimetresToTheSixth) { UN.QuantityValue qv = centimetresToTheSixth; diff --git a/Units_Engine/Query/UnitSymbol.cs b/Units_Engine/Query/UnitSymbol.cs deleted file mode 100644 index 8ed6d09..0000000 --- a/Units_Engine/Query/UnitSymbol.cs +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of the Buildings and Habitats object Model (BHoM) - * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. - * - * Each contributor holds copyright over their respective contributions. - * The project versioning (Git) records all such contribution source information. - * - * - * The BHoM is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3.0 of the License, or - * (at your option) any later version. - * - * The BHoM is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this code. If not, see . - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Globalization; - -using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes - -using BH.oM.Base.Attributes; -using BH.Engine.Base; - -namespace BH.Engine.Units -{ - public static partial class Query - { - /***************************************************/ - /**** Public Methods ****/ - /***************************************************/ - - [Description("The engineer-facing symbol for a unit, read from UnitsNet, e.g. LengthUnit.Millimeter " + - "-> \"mm\" and AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\". UnitsNet is the only " + - "thing in the stack that names a unit; a BH.oM.Units member carries no symbol of its own.")] - [Input("unit", "A member of one of the BH.oM.Units unit enums, e.g. LengthUnit.Millimeter.")] - [Output("symbol", "The unit's display symbol, or an empty string for a unit UnitsNet does not know.")] - public static string UnitSymbol(this Enum unit) - { - Type netUnitType; - int netUnitValue; - if (!TryResolveUnitsNetUnit(unit, out netUnitType, out netUnitValue)) - return ""; - - // The list, not GetDefaultAbbreviation: the list comes back empty for a unit UnitsNet has - // registered no symbol for, where the single-value call is only safe once the unit is known to be - // defined. Element 0 is the default abbreviation for every unit UnitsNet publishes. - string[] symbols = UN.UnitsNetSetup.Default.UnitAbbreviations - .GetUnitAbbreviations(netUnitType, netUnitValue, CultureInfo.CurrentCulture); - - if (symbols.Length == 0) - { - Compute.RecordError($"UnitsNet publishes no symbol for {unit}."); - return ""; - } - - return symbols[0]; - } - - /***************************************************/ - /**** Private Methods ****/ - /***************************************************/ - - // The bridge to UnitsNet is by NAME, not value: their integer values disagree for LengthUnit, - // AngleUnit, PressureUnit and others, so a cast would hand back a different unit (Radian -> Revolution). - // Convert.ToBHoMUnit runs the same bridge in the opposite direction. - private static bool TryResolveUnitsNetUnit(Enum unit, out Type netUnitType, out int netUnitValue) - { - netUnitType = null; - netUnitValue = 0; - - if (unit == null) - { - Compute.RecordError("A unit symbol can only be taken from a unit enum member."); - return false; - } - - Type bhomType = unit.GetType(); - - lock (m_UnitsNetTypes) - { - if (!m_UnitsNetTypes.TryGetValue(bhomType, out netUnitType)) - { - netUnitType = bhomType.Namespace == "UnitsNet.Units" - ? bhomType - : typeof(UN.UnitsNetSetup).Assembly.GetType("UnitsNet.Units." + bhomType.Name); - - m_UnitsNetTypes[bhomType] = netUnitType; - } - } - - if (netUnitType == null) - { - Compute.RecordError($"UnitsNet has no {bhomType.Name}, so {unit} has no symbol."); - return false; - } - - string name = unit.ToString(); - if (!Enum.IsDefined(netUnitType, name)) - { - // BH.oM.Units's own Undefined, and anything BHoM has added since, lands here. - Compute.RecordError($"UnitsNet's {netUnitType.Name} has no {name}, so it has no symbol."); - return false; - } - - netUnitValue = System.Convert.ToInt32(Enum.Parse(netUnitType, name)); - return true; - } - - /***************************************************/ - /**** Private Fields ****/ - /***************************************************/ - - // One reflection lookup per unit enum type, not per call. - private static readonly Dictionary m_UnitsNetTypes = new Dictionary(); - - /***************************************************/ - } -} From d652f8eb4baa1ea0ae13493daae94846c9ffdb44 Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Thu, 3 Sep 2026 13:27:26 +0100 Subject: [PATCH 11/14] Update UnitSymbol to switch method. Refactor Converts to Internal --- .../Convert/Acceleration/Acceleration.cs | 4 +- Units_Engine/Convert/Angle/Angle.cs | 4 +- Units_Engine/Convert/Area/Area.cs | 4 +- .../AreaMomentOfInertia.cs | 4 +- .../CoefficientOfThermalExpansion.cs | 4 +- Units_Engine/Convert/Density/Density.cs | 4 +- Units_Engine/Convert/Duration/Duration.cs | 4 +- .../ElectricConductivity.cs | 4 +- Units_Engine/Convert/Energy/Energy.cs | 4 +- Units_Engine/Convert/Force/Force.cs | 4 +- .../Convert/ForcePerLength/ForcePerLength.cs | 4 +- Units_Engine/Convert/Length/Length.cs | 4 +- Units_Engine/Convert/Mass/Mass.cs | 4 +- .../Convert/MassFraction/MassFraction.cs | 4 +- Units_Engine/Convert/Molality/Molality.cs | 4 +- .../MomentPerLength/MomentPerLength.cs | 4 +- Units_Engine/Convert/Pressure/Pressure.cs | 4 +- Units_Engine/Convert/Speed/Speed.cs | 4 +- .../Convert/Temperature/Temperature.cs | 4 +- .../TemperatureDelta/TemperatureDelta.cs | 4 +- Units_Engine/Convert/Torque/Torque.cs | 4 +- Units_Engine/Convert/Volume/Volume.cs | 4 +- Units_Engine/Query/UnitSymbol.cs | 121 ++++++++++++++++++ 23 files changed, 165 insertions(+), 44 deletions(-) create mode 100644 Units_Engine/Query/UnitSymbol.cs diff --git a/Units_Engine/Convert/Acceleration/Acceleration.cs b/Units_Engine/Convert/Acceleration/Acceleration.cs index cd31c61..3605b99 100644 --- a/Units_Engine/Convert/Acceleration/Acceleration.cs +++ b/Units_Engine/Convert/Acceleration/Acceleration.cs @@ -91,10 +91,10 @@ public static double ToAcceleration(this double metresPerSecondSquared, object u } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.AccelerationUnit? ToAccelerationUnit(object unit) + internal static UNU.AccelerationUnit? ToAccelerationUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Angle/Angle.cs b/Units_Engine/Convert/Angle/Angle.cs index a92b70e..8acd8b9 100644 --- a/Units_Engine/Convert/Angle/Angle.cs +++ b/Units_Engine/Convert/Angle/Angle.cs @@ -92,10 +92,10 @@ public static double ToAngle(this double radian, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.AngleUnit? ToAngleUnit(object unit) + internal static UNU.AngleUnit? ToAngleUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Area/Area.cs b/Units_Engine/Convert/Area/Area.cs index 1918da1..dfc28ce 100644 --- a/Units_Engine/Convert/Area/Area.cs +++ b/Units_Engine/Convert/Area/Area.cs @@ -91,10 +91,10 @@ public static double ToArea(this double squareMetres, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.AreaUnit? ToAreaUnit(object unit) + internal static UNU.AreaUnit? ToAreaUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/AreaMomentOfInertia/AreaMomentOfInertia.cs b/Units_Engine/Convert/AreaMomentOfInertia/AreaMomentOfInertia.cs index a678f76..f8938fd 100644 --- a/Units_Engine/Convert/AreaMomentOfInertia/AreaMomentOfInertia.cs +++ b/Units_Engine/Convert/AreaMomentOfInertia/AreaMomentOfInertia.cs @@ -91,10 +91,10 @@ public static double ToAreaMomentOfInertia(this double metresToTheFourth, object } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.AreaMomentOfInertiaUnit? ToAreaMomentOfInertiaUnit(object unit) + internal static UNU.AreaMomentOfInertiaUnit? ToAreaMomentOfInertiaUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/CoefficientOfThermalExpansion/CoefficientOfThermalExpansion.cs b/Units_Engine/Convert/CoefficientOfThermalExpansion/CoefficientOfThermalExpansion.cs index ed861ef..c8dfac7 100644 --- a/Units_Engine/Convert/CoefficientOfThermalExpansion/CoefficientOfThermalExpansion.cs +++ b/Units_Engine/Convert/CoefficientOfThermalExpansion/CoefficientOfThermalExpansion.cs @@ -91,10 +91,10 @@ public static double ToCoefficientOfThermalExpansion(this double inverseDeltaKel } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.CoefficientOfThermalExpansionUnit? ToCoefficientOfThermalExpansionUnit(object unit) + internal static UNU.CoefficientOfThermalExpansionUnit? ToCoefficientOfThermalExpansionUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Density/Density.cs b/Units_Engine/Convert/Density/Density.cs index 7fc854d..31199bc 100644 --- a/Units_Engine/Convert/Density/Density.cs +++ b/Units_Engine/Convert/Density/Density.cs @@ -91,10 +91,10 @@ public static double ToDensity(this double kilogramPerCubicMetres, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.DensityUnit? ToDensityUnit(object unit) + internal static UNU.DensityUnit? ToDensityUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Duration/Duration.cs b/Units_Engine/Convert/Duration/Duration.cs index 3bf32d2..2fb19e6 100644 --- a/Units_Engine/Convert/Duration/Duration.cs +++ b/Units_Engine/Convert/Duration/Duration.cs @@ -88,10 +88,10 @@ public static double ToDuration(this double seconds, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.DurationUnit? ToDurationUnit(object unit) + internal static UNU.DurationUnit? ToDurationUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/ElectricConductivity/ElectricConductivity.cs b/Units_Engine/Convert/ElectricConductivity/ElectricConductivity.cs index 3966281..ada5fc2 100644 --- a/Units_Engine/Convert/ElectricConductivity/ElectricConductivity.cs +++ b/Units_Engine/Convert/ElectricConductivity/ElectricConductivity.cs @@ -92,10 +92,10 @@ public static double ToElectricConductivity(this double siemensPerMetre, object } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.ElectricConductivityUnit? ToElectricConductivityUnit(object unit) + internal static UNU.ElectricConductivityUnit? ToElectricConductivityUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Energy/Energy.cs b/Units_Engine/Convert/Energy/Energy.cs index 16200c3..e0a25a7 100644 --- a/Units_Engine/Convert/Energy/Energy.cs +++ b/Units_Engine/Convert/Energy/Energy.cs @@ -92,10 +92,10 @@ public static double ToEnergy(this double joule, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.EnergyUnit? ToEnergyUnit(object unit) + internal static UNU.EnergyUnit? ToEnergyUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Force/Force.cs b/Units_Engine/Convert/Force/Force.cs index 64a9191..4efba60 100644 --- a/Units_Engine/Convert/Force/Force.cs +++ b/Units_Engine/Convert/Force/Force.cs @@ -92,10 +92,10 @@ public static double ToForce(this double newtons, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.ForceUnit? ToForceUnit(object unit) + internal static UNU.ForceUnit? ToForceUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/ForcePerLength/ForcePerLength.cs b/Units_Engine/Convert/ForcePerLength/ForcePerLength.cs index b236741..5b972c7 100644 --- a/Units_Engine/Convert/ForcePerLength/ForcePerLength.cs +++ b/Units_Engine/Convert/ForcePerLength/ForcePerLength.cs @@ -91,10 +91,10 @@ public static double ToForcePerLength(this double newtonPerMetre, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.ForcePerLengthUnit? ToForcePerLengthUnit(object unit) + internal static UNU.ForcePerLengthUnit? ToForcePerLengthUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Length/Length.cs b/Units_Engine/Convert/Length/Length.cs index 8d574c1..f9eabae 100644 --- a/Units_Engine/Convert/Length/Length.cs +++ b/Units_Engine/Convert/Length/Length.cs @@ -91,10 +91,10 @@ public static double ToLength(this double metres, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.LengthUnit? ToLengthUnit(object unit) + internal static UNU.LengthUnit? ToLengthUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Mass/Mass.cs b/Units_Engine/Convert/Mass/Mass.cs index 3a9d919..76f459f 100644 --- a/Units_Engine/Convert/Mass/Mass.cs +++ b/Units_Engine/Convert/Mass/Mass.cs @@ -91,10 +91,10 @@ public static double ToMass(this double kilogram, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.MassUnit? ToMassUnit(object unit) + internal static UNU.MassUnit? ToMassUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/MassFraction/MassFraction.cs b/Units_Engine/Convert/MassFraction/MassFraction.cs index 6fd599d..1a62dc8 100644 --- a/Units_Engine/Convert/MassFraction/MassFraction.cs +++ b/Units_Engine/Convert/MassFraction/MassFraction.cs @@ -86,9 +86,9 @@ public static double ToMassFraction(this double kilogramsPerKilogram, object uni } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.MassFractionUnit? ToMassFractionUnit(object unit) + internal static UNU.MassFractionUnit? ToMassFractionUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Molality/Molality.cs b/Units_Engine/Convert/Molality/Molality.cs index 05660f1..4e469a8 100644 --- a/Units_Engine/Convert/Molality/Molality.cs +++ b/Units_Engine/Convert/Molality/Molality.cs @@ -88,10 +88,10 @@ public static double ToMolality(this double molePerKilograms, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.MolalityUnit? ToMolalityUnit(object unit) + internal static UNU.MolalityUnit? ToMolalityUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/MomentPerLength/MomentPerLength.cs b/Units_Engine/Convert/MomentPerLength/MomentPerLength.cs index ed71c9e..819a50e 100644 --- a/Units_Engine/Convert/MomentPerLength/MomentPerLength.cs +++ b/Units_Engine/Convert/MomentPerLength/MomentPerLength.cs @@ -91,10 +91,10 @@ public static double ToMomentPerLength(this double newtonMeterPerMeter, object u } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.TorquePerLengthUnit? ToTorquePerLengthUnit(object unit) + internal static UNU.TorquePerLengthUnit? ToTorquePerLengthUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Pressure/Pressure.cs b/Units_Engine/Convert/Pressure/Pressure.cs index 2664f5b..5f5f18b 100644 --- a/Units_Engine/Convert/Pressure/Pressure.cs +++ b/Units_Engine/Convert/Pressure/Pressure.cs @@ -91,10 +91,10 @@ public static double ToPressure(this double pascal, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.PressureUnit? ToPressureUnit(this object unit) + internal static UNU.PressureUnit? ToPressureUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Speed/Speed.cs b/Units_Engine/Convert/Speed/Speed.cs index 2d8e37b..dfdab08 100644 --- a/Units_Engine/Convert/Speed/Speed.cs +++ b/Units_Engine/Convert/Speed/Speed.cs @@ -91,10 +91,10 @@ public static double ToSpeed(this double metresPerSecond, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.SpeedUnit? ToSpeedUnit(object unit) + internal static UNU.SpeedUnit? ToSpeedUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Temperature/Temperature.cs b/Units_Engine/Convert/Temperature/Temperature.cs index 5304d48..ed7036b 100644 --- a/Units_Engine/Convert/Temperature/Temperature.cs +++ b/Units_Engine/Convert/Temperature/Temperature.cs @@ -91,10 +91,10 @@ public static double ToTemperature(this double celsius, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.TemperatureUnit? ToTemperatureUnit(object unit) + internal static UNU.TemperatureUnit? ToTemperatureUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/TemperatureDelta/TemperatureDelta.cs b/Units_Engine/Convert/TemperatureDelta/TemperatureDelta.cs index cc25736..009d0ba 100644 --- a/Units_Engine/Convert/TemperatureDelta/TemperatureDelta.cs +++ b/Units_Engine/Convert/TemperatureDelta/TemperatureDelta.cs @@ -91,10 +91,10 @@ public static double ToTemperatureDelta(this double kelvin, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.TemperatureDeltaUnit? ToTemperatureDeltaUnit(object unit) + internal static UNU.TemperatureDeltaUnit? ToTemperatureDeltaUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Torque/Torque.cs b/Units_Engine/Convert/Torque/Torque.cs index 3d7d024..e82285e 100644 --- a/Units_Engine/Convert/Torque/Torque.cs +++ b/Units_Engine/Convert/Torque/Torque.cs @@ -92,10 +92,10 @@ public static double ToTorque(this double newtonMeter, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.TorqueUnit? ToTorqueUnit(object unit) + internal static UNU.TorqueUnit? ToTorqueUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Convert/Volume/Volume.cs b/Units_Engine/Convert/Volume/Volume.cs index 9fc66c0..e2b0ab5 100644 --- a/Units_Engine/Convert/Volume/Volume.cs +++ b/Units_Engine/Convert/Volume/Volume.cs @@ -88,10 +88,10 @@ public static double ToVolume(this double cubicMeter, object unit) } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.VolumeUnit? ToVolumeUnit(object unit) + internal static UNU.VolumeUnit? ToVolumeUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Query/UnitSymbol.cs b/Units_Engine/Query/UnitSymbol.cs new file mode 100644 index 0000000..dea78b5 --- /dev/null +++ b/Units_Engine/Query/UnitSymbol.cs @@ -0,0 +1,121 @@ +/* + * This file is part of the Buildings and Habitats object Model (BHoM) + * Copyright (c) 2015 - 2026, the respective contributors. All rights reserved. + * + * Each contributor holds copyright over their respective contributions. + * The project versioning (Git) records all such contribution source information. + * + * + * The BHoM is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3.0 of the License, or + * (at your option) any later version. + * + * The BHoM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this code. If not, see . + */ + +using System; +using System.ComponentModel; +using System.Globalization; + +using UN = UnitsNet; //This is to avoid clashes between UnitsNet quantity attributes and BHoM quantity attributes + +using BH.oM.Base.Attributes; +using BH.oM.Units; +using BH.Engine.Base; + +namespace BH.Engine.Units +{ + public static partial class Query + { + /***************************************************/ + /**** Public Methods ****/ + /***************************************************/ + + [Description("The engineer-facing symbol for a unit, e.g. LengthUnit.Millimeter -> \"mm\" and " + + "AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\". The symbol itself comes from UnitsNet: " + + "UnitsNet is the only thing in the stack that names a unit, and a BH.oM.Units member carries no " + + "symbol of its own.")] + [Input("unit", "A member of one of the BH.oM.Units unit enums, e.g. LengthUnit.Millimeter.")] + [Output("symbol", "The unit's display symbol, or an empty string for a unit with no symbol.")] + public static string UnitSymbol(this Enum unit) + { + if (unit == null) + { + Compute.RecordError("A unit symbol can only be taken from a unit enum member."); + return ""; + } + + switch (unit.GetType().Name) + { + case nameof(LengthUnit): return Symbol(unit, Convert.ToLengthUnit(unit)); + case nameof(AreaUnit): return Symbol(unit, Convert.ToAreaUnit(unit)); + case nameof(VolumeUnit): return Symbol(unit, Convert.ToVolumeUnit(unit)); + case nameof(AreaMomentOfInertiaUnit): return Symbol(unit, Convert.ToAreaMomentOfInertiaUnit(unit)); + case nameof(PressureUnit): return Symbol(unit, Convert.ToPressureUnit(unit)); + case nameof(ForceUnit): return Symbol(unit, Convert.ToForceUnit(unit)); + case nameof(TorqueUnit): return Symbol(unit, Convert.ToTorqueUnit(unit)); + case nameof(ForcePerLengthUnit): return Symbol(unit, Convert.ToForcePerLengthUnit(unit)); + case nameof(TorquePerLengthUnit): return Symbol(unit, Convert.ToTorquePerLengthUnit(unit)); + case nameof(MassUnit): return Symbol(unit, Convert.ToMassUnit(unit)); + case nameof(AngleUnit): return Symbol(unit, Convert.ToAngleUnit(unit)); + case nameof(AccelerationUnit): return Symbol(unit, Convert.ToAccelerationUnit(unit)); + case nameof(DensityUnit): return Symbol(unit, Convert.ToDensityUnit(unit)); + case nameof(EnergyUnit): return Symbol(unit, Convert.ToEnergyUnit(unit)); + case nameof(SpeedUnit): return Symbol(unit, Convert.ToSpeedUnit(unit)); + case nameof(DurationUnit): return Symbol(unit, Convert.ToDurationUnit(unit)); + case nameof(TemperatureUnit): return Symbol(unit, Convert.ToTemperatureUnit(unit)); + case nameof(TemperatureDeltaUnit): return Symbol(unit, Convert.ToTemperatureDeltaUnit(unit)); + case nameof(CoefficientOfThermalExpansionUnit): return Symbol(unit, Convert.ToCoefficientOfThermalExpansionUnit(unit)); + case nameof(ElectricConductivityUnit): return Symbol(unit, Convert.ToElectricConductivityUnit(unit)); + case nameof(MassFractionUnit): return Symbol(unit, Convert.ToMassFractionUnit(unit)); + case nameof(MolalityUnit): return Symbol(unit, Convert.ToMolalityUnit(unit)); + + default: + Compute.RecordError($"BH.Engine.Units has no symbol for a {unit.GetType().Name}."); + return ""; + } + } + + /***************************************************/ + /**** Private Methods ****/ + /***************************************************/ + + // The bridge to UnitsNet is Convert's per-quantity mapper, the same one the conversions go through, + // so a symbol and a conversion can never disagree about which UnitsNet unit a BHoM unit is. It cannot + // be a cast - the integer values disagree for LengthUnit, AngleUnit, PressureUnit and others, so a + // cast would hand back a different unit (Radian -> Revolution) - and it cannot be by name either: + // BH.oM.Units spells SiemensPerMetre where UnitsNet spells SiemensPerMeter. + private static string Symbol(Enum unit, T? netUnit) where T : struct, Enum + { + if (netUnit == null) + { + // BH.oM.Units's own Undefined, and anything BHoM has added that UnitsNet has no unit for. + Compute.RecordError($"BH.Engine.Units cannot map {unit.GetType().Name}.{unit} to a " + + "UnitsNet unit, so it has no symbol."); + return ""; + } + + string symbol = UN.UnitsNetSetup.Default.UnitAbbreviations + .GetDefaultAbbreviation(netUnit.Value, CultureInfo.CurrentCulture); + + if (string.IsNullOrEmpty(symbol)) + { + // UnitsNet knows the unit but has registered no abbreviation for it. At 5.55.0 that is + // VolumeUnit.MetricCup and the six other spoon-and-cup units, and nothing else. + Compute.RecordError($"UnitsNet publishes no symbol for {unit.GetType().Name}.{unit}."); + return ""; + } + + return symbol; + } + + /***************************************************/ + } +} From 3b06aaa14aa4fd55e698f74d0f769a82206855cf Mon Sep 17 00:00:00 2001 From: Christopher Short Date: Fri, 4 Sep 2026 12:51:57 +0100 Subject: [PATCH 12/14] Add WarpingMoment --- .../Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs | 4 ++-- Units_Engine/Query/UnitSymbol.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs b/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs index 525fb06..9a5edd6 100644 --- a/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs +++ b/Units_Engine/Convert/WarpingMomentOfInertia/WarpingMomentOfInertia.cs @@ -85,10 +85,10 @@ public static double ToWarpingMomentOfInertia(this double metresToTheSixth, obje } /***************************************************/ - /**** Private Methods ****/ + /**** Internal Methods ****/ /***************************************************/ - private static UNU.WarpingMomentOfInertiaUnit? ToWarpingMomentOfInertiaUnit(object unit) + internal static UNU.WarpingMomentOfInertiaUnit? ToWarpingMomentOfInertiaUnit(object unit) { if (unit == null || unit.ToString() == null) return null; diff --git a/Units_Engine/Query/UnitSymbol.cs b/Units_Engine/Query/UnitSymbol.cs index dea78b5..f856ec4 100644 --- a/Units_Engine/Query/UnitSymbol.cs +++ b/Units_Engine/Query/UnitSymbol.cs @@ -58,6 +58,7 @@ public static string UnitSymbol(this Enum unit) case nameof(AreaUnit): return Symbol(unit, Convert.ToAreaUnit(unit)); case nameof(VolumeUnit): return Symbol(unit, Convert.ToVolumeUnit(unit)); case nameof(AreaMomentOfInertiaUnit): return Symbol(unit, Convert.ToAreaMomentOfInertiaUnit(unit)); + case nameof(WarpingMomentOfInertiaUnit): return Symbol(unit, Convert.ToWarpingMomentOfInertiaUnit(unit)); case nameof(PressureUnit): return Symbol(unit, Convert.ToPressureUnit(unit)); case nameof(ForceUnit): return Symbol(unit, Convert.ToForceUnit(unit)); case nameof(TorqueUnit): return Symbol(unit, Convert.ToTorqueUnit(unit)); From 68c3ca4b80f5cee58937969da9311fa02a80d9a2 Mon Sep 17 00:00:00 2001 From: Peter Nugent Date: Fri, 4 Sep 2026 19:49:22 +0100 Subject: [PATCH 13/14] Update descriptions --- Units_Engine/Query/UnitSymbol.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Units_Engine/Query/UnitSymbol.cs b/Units_Engine/Query/UnitSymbol.cs index f856ec4..924772e 100644 --- a/Units_Engine/Query/UnitSymbol.cs +++ b/Units_Engine/Query/UnitSymbol.cs @@ -39,10 +39,8 @@ public static partial class Query /***************************************************/ [Description("The engineer-facing symbol for a unit, e.g. LengthUnit.Millimeter -> \"mm\" and " + - "AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\". The symbol itself comes from UnitsNet: " + - "UnitsNet is the only thing in the stack that names a unit, and a BH.oM.Units member carries no " + - "symbol of its own.")] - [Input("unit", "A member of one of the BH.oM.Units unit enums, e.g. LengthUnit.Millimeter.")] + "AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\.")] + [Input("unit", "A member of one of the unit enums, e.g. LengthUnit.Millimeter.")] [Output("symbol", "The unit's display symbol, or an empty string for a unit with no symbol.")] public static string UnitSymbol(this Enum unit) { From 83356274a9396432db796b7cb50ddf04b6e94c09 Mon Sep 17 00:00:00 2001 From: Peter Nugent Date: Fri, 4 Sep 2026 19:55:27 +0100 Subject: [PATCH 14/14] Update UnitSymbol.cs --- Units_Engine/Query/UnitSymbol.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Units_Engine/Query/UnitSymbol.cs b/Units_Engine/Query/UnitSymbol.cs index 924772e..a7d0023 100644 --- a/Units_Engine/Query/UnitSymbol.cs +++ b/Units_Engine/Query/UnitSymbol.cs @@ -39,7 +39,7 @@ public static partial class Query /***************************************************/ [Description("The engineer-facing symbol for a unit, e.g. LengthUnit.Millimeter -> \"mm\" and " + - "AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\.")] + "AreaMomentOfInertiaUnit.CentimeterToTheFourth -> \"cm⁴\".")] [Input("unit", "A member of one of the unit enums, e.g. LengthUnit.Millimeter.")] [Output("symbol", "The unit's display symbol, or an empty string for a unit with no symbol.")] public static string UnitSymbol(this Enum unit)