diff --git a/openVulkanoCpp/Base/UnitFormatter.cpp b/openVulkanoCpp/Base/UnitFormatter.cpp new file mode 100644 index 0000000..a2ee422 --- /dev/null +++ b/openVulkanoCpp/Base/UnitFormatter.cpp @@ -0,0 +1,93 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include "UnitFormatter.hpp" +#include +#include +#include + +namespace +{ + template + std::string FormatValue(T value, int precision, bool trimTrailingZeros, const std::string& suffix) + { + std::ostringstream out; + out << std::fixed << std::setprecision(precision) << value; + std::string result = out.str(); + + if (trimTrailingZeros && result.find('.') != std::string::npos) + { + result.erase(result.find_last_not_of('0') + 1); + + if (result.back() == '.') + { + result.pop_back(); + } + } + result += suffix; + return result; + } +} + +namespace OpenVulkano +{ + UnitFormatter::UnitFormatter(bool useMetric, int precisionDigits, bool doTrimTrailingZeros) + : metric(useMetric), precision(precisionDigits), trimTrailingZeros(doTrimTrailingZeros) + { + } + + std::string UnitFormatter::Format(units::length::meter_t distance) const + { + if (metric) + { + if (distance > units::length::meter_t(0) && distance < units::length::meter_t(0.1)) + { + return FormatValue(units::length::millimeter_t(distance).value(), precision, trimTrailingZeros, " mm"); + } + else if (distance >= units::length::kilometer_t(1)) + { + return FormatValue(units::length::kilometer_t(distance).value(), precision, trimTrailingZeros, " km"); + } + return FormatValue(distance.value(), precision, trimTrailingZeros, " m"); + } + else + { + auto distanceFeet = units::length::foot_t(distance).value(); + auto distanceInches = units::length::inch_t(distance).value(); + + if (distanceFeet > 0 && distanceFeet < 0.1) + { + return FormatValue(distanceInches, precision, trimTrailingZeros, " in"); + } + else if (distanceFeet >= 5280.0) + { + return FormatValue(units::length::mile_t(distance).value(), precision, trimTrailingZeros, " mi"); + } + return FormatValue(distanceFeet, precision, trimTrailingZeros, " ft"); + } + } + + std::string UnitFormatter::Format(units::area::square_meter_t area) const + { + if (metric) + { + if (area >= units::area::square_kilometer_t(1)) + { + return FormatValue(units::area::square_kilometer_t(area).value(), precision, trimTrailingZeros, " km²"); + } + return FormatValue(area.value(), precision, trimTrailingZeros, " m²"); + } + else + { + auto areaSquareFeet = units::area::square_foot_t(area).value(); + if (areaSquareFeet >= 27878400.0) + { + return FormatValue(units::area::square_mile_t(area).value(), precision, trimTrailingZeros, " mi²"); + } + return FormatValue(areaSquareFeet, precision, trimTrailingZeros, " ft²"); + } + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Base/UnitFormatter.hpp b/openVulkanoCpp/Base/UnitFormatter.hpp new file mode 100644 index 0000000..3e17543 --- /dev/null +++ b/openVulkanoCpp/Base/UnitFormatter.hpp @@ -0,0 +1,24 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ +#pragma once + +#include +#include + +namespace OpenVulkano +{ + class UnitFormatter + { + bool metric = true; + int precision = 3; + bool trimTrailingZeros = true; + + public: + UnitFormatter(bool useMetric = true, int precisionDigits = 3, bool doTrimTrailingZeros = true); + [[nodiscard]] std::string Format(units::length::meter_t distance) const; + [[nodiscard]] std::string Format(units::area::square_meter_t area) const; + }; +} \ No newline at end of file diff --git a/tests/UnitFormatter.cpp b/tests/UnitFormatter.cpp new file mode 100644 index 0000000..8f2d2b3 --- /dev/null +++ b/tests/UnitFormatter.cpp @@ -0,0 +1,68 @@ +/* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include + +#include "Base/UnitFormatter.hpp" + +using namespace units::literals; + +TEST_CASE("testUnitFormatterWithTrailingZeros", "[UnitFormatter]") +{ + OpenVulkano::UnitFormatter metricFormatter(true, 2, false); + OpenVulkano::UnitFormatter imperialFormatter(false, 2, false); + + units::length::meter_t positiveDistance = 1500.0_m; + units::length::meter_t smallDistance = 0.5_m; + units::length::meter_t negativeDistance = -100.0_m; + units::length::meter_t smallDistanceMetric = 0.05_m; + units::length::meter_t smallDistanceImperial = 0.03_m; + units::area::square_meter_t smallArea(0.005); + units::area::square_meter_t negativeArea(-50.0); + + REQUIRE(metricFormatter.Format(positiveDistance) == "1.50 km"); + REQUIRE(metricFormatter.Format(smallDistance) == "0.50 m"); + REQUIRE(metricFormatter.Format(negativeDistance) == "-100.00 m"); + REQUIRE(metricFormatter.Format(smallArea) == "0.01 m²"); + REQUIRE(metricFormatter.Format(negativeArea) == "-50.00 m²"); + REQUIRE(imperialFormatter.Format(smallDistance) == "1.64 ft"); + REQUIRE(imperialFormatter.Format(negativeDistance) == "-328.08 ft"); + REQUIRE(imperialFormatter.Format(smallArea) == "0.05 ft²"); + REQUIRE(imperialFormatter.Format(negativeArea) == "-538.20 ft²"); + REQUIRE(metricFormatter.Format(smallDistanceMetric) == "50.00 mm"); + REQUIRE(imperialFormatter.Format(smallDistanceImperial) == "1.18 in"); +} + +TEST_CASE("testUnitFormatterWithoutTrailingZeros", "[UnitFormatter]") +{ + OpenVulkano::UnitFormatter metricFormatter(true, 2); + OpenVulkano::UnitFormatter imperialFormatter(false, 2); + + units::length::meter_t positiveDistance = 1500.0_m; + units::length::meter_t smallDistance = 0.5_m; + units::length::meter_t negativeDistance = -100.0_m; + units::length::meter_t smallDistanceMetric = 0.05_m; + units::length::meter_t smallDistanceImperial = 0.03_m; + units::length::meter_t mediumDistanceMetric = 0.5_m; + units::length::meter_t largeDistanceMetric = 100.0_m; + units::area::square_meter_t smallArea(0.005); + units::area::square_meter_t negativeArea(-50.0); + + REQUIRE(metricFormatter.Format(positiveDistance) == "1.5 km"); + REQUIRE(metricFormatter.Format(smallDistance) == "0.5 m"); + REQUIRE(metricFormatter.Format(negativeDistance) == "-100 m"); + REQUIRE(metricFormatter.Format(smallArea) == "0.01 m²"); + REQUIRE(metricFormatter.Format(negativeArea) == "-50 m²"); + REQUIRE(imperialFormatter.Format(smallDistance) == "1.64 ft"); + REQUIRE(imperialFormatter.Format(negativeDistance) == "-328.08 ft"); + REQUIRE(imperialFormatter.Format(smallArea) == "0.05 ft²"); + REQUIRE(imperialFormatter.Format(negativeArea) == "-538.2 ft²"); + REQUIRE(metricFormatter.Format(smallDistanceMetric) == "50 mm"); + REQUIRE(imperialFormatter.Format(smallDistanceImperial) == "1.18 in"); + REQUIRE(metricFormatter.Format(smallDistanceMetric) == "50 mm"); + REQUIRE(metricFormatter.Format(mediumDistanceMetric) == "0.5 m"); + REQUIRE(metricFormatter.Format(largeDistanceMetric) == "100 m"); +} \ No newline at end of file