KiCad PCB EDA Suite
Loading...
Searching...
No Matches
text_eval_units.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <kicommon.h>
23#include <magic_enum.hpp>
24#include <string>
25#include <string_view>
26#include <vector>
27#include <array>
28#include <algorithm>
29#include <optional>
30
31namespace text_eval_units {
32
40enum class Unit {
41 // Multi-character composite units (longest first for proper parsing)
42 PS_PER_MM, // "ps/mm" - picoseconds per millimeter
43 PS_PER_CM, // "ps/cm" - picoseconds per centimeter
44 PS_PER_IN, // "ps/in" - picoseconds per inch
45
46 // Multi-character simple units
47 THOU, // "thou" - thousandths of an inch (same as mil)
48 DEG, // "deg" - degrees
49
50 // Common single and double character units
51 MM, // "mm" - millimeters
52 CM, // "cm" - centimeters
53 INCH, // "in" - inches
54 MIL, // "mil" - mils (thousandths of an inch)
55 UM, // "um" - micrometers
56 PS, // "ps" - picoseconds
57 FS, // "fs" - femtoseconds
58
59 // Single character units
60 INCH_QUOTE, // "\"" - inches (using quote character)
61 DEGREE_SYMBOL, // "°" - degrees (using degree symbol)
62
63 // Invalid/unknown unit
65};
66
75public:
79 struct UnitInfo {
81 std::string_view unitString;
82 std::string_view description;
83 double conversionToMM; // Conversion factor to millimeters (base unit)
84 };
85
86private:
87 // Static unit information table ordered by parsing priority (longest first)
88 static constexpr std::array<UnitInfo, 15> s_unitTable = {{
89 // Multi-character composite units first (longest matches)
90 {Unit::PS_PER_MM, "ps/mm", "Picoseconds per millimeter", 1.0},
91 {Unit::PS_PER_CM, "ps/cm", "Picoseconds per centimeter", 1.0},
92 {Unit::PS_PER_IN, "ps/in", "Picoseconds per inch", 1.0},
93
94 // Multi-character simple units
95 {Unit::THOU, "thou", "Thousandths of an inch", 25.4 / 1000.0},
96 {Unit::DEG, "deg", "Degrees", 1.0},
97
98 // Common units
99 {Unit::MM, "mm", "Millimeters", 1.0},
100 {Unit::CM, "cm", "Centimeters", 10.0},
101 {Unit::INCH, "in", "Inches", 25.4},
102 {Unit::MIL, "mil", "Mils (thousandths of an inch)", 25.4 / 1000.0},
103 {Unit::UM, "um", "Micrometers", 1.0 / 1000.0},
104 {Unit::PS, "ps", "Picoseconds", 1.0},
105 {Unit::FS, "fs", "Femtoseconds", 1.0},
106
107 // Single character units (must be last for proper parsing)
108 {Unit::INCH_QUOTE, "\"", "Inches (quote notation)", 25.4},
109 {Unit::DEGREE_SYMBOL, "°", "Degrees (symbol)", 1.0},
110
111 // Invalid marker
112 {Unit::INVALID, "", "Invalid/unknown unit", 1.0}
113 }};
114
115public:
121 static constexpr Unit parseUnit(std::string_view unitStr) noexcept {
122 if (unitStr.empty()) {
123 return Unit::INVALID;
124 }
125
126 // Search through unit table (ordered by priority)
127 for (const auto& info : s_unitTable) {
128 if (info.unit != Unit::INVALID && info.unitString == unitStr) {
129 return info.unit;
130 }
131 }
132
133 return Unit::INVALID;
134 }
135
141 static constexpr std::string_view getUnitString(Unit unit) noexcept {
142 for (const auto& info : s_unitTable) {
143 if (info.unit == unit) {
144 return info.unitString;
145 }
146 }
147 return "";
148 }
149
154 static std::vector<std::string> getAllUnitStrings() {
155 std::vector<std::string> units;
156 units.reserve(s_unitTable.size() - 1); // Exclude INVALID
157
158 for (const auto& info : s_unitTable) {
159 if (info.unit != Unit::INVALID && !info.unitString.empty()) {
160 units.emplace_back(info.unitString);
161 }
162 }
163
164 return units;
165 }
166
173 static constexpr double getConversionFactor(Unit fromUnit, Unit toUnit) noexcept {
174 if (fromUnit == toUnit) {
175 return 1.0;
176 }
177
178 // Find conversion factors for both units
179 double fromToMM = 1.0;
180 double toFromMM = 1.0;
181
182 for (const auto& info : s_unitTable) {
183 if (info.unit == fromUnit) {
184 fromToMM = info.conversionToMM;
185 } else if (info.unit == toUnit) {
186 toFromMM = 1.0 / info.conversionToMM;
187 }
188 }
189
190 return fromToMM * toFromMM;
191 }
192
198 static constexpr Unit fromEdaUnits(EDA_UNITS edaUnits) noexcept {
199 switch (edaUnits) {
200 case EDA_UNITS::MM: return Unit::MM;
201 case EDA_UNITS::CM: return Unit::CM;
202 case EDA_UNITS::MILS: return Unit::MIL;
203 case EDA_UNITS::INCH: return Unit::INCH;
204 case EDA_UNITS::DEGREES: return Unit::DEG;
205 case EDA_UNITS::FS: return Unit::FS;
206 case EDA_UNITS::PS: return Unit::PS;
210 case EDA_UNITS::UM: return Unit::UM;
211 default: return Unit::MM; // Default fallback
212 }
213 }
214
222 static constexpr double convertValue(double value, Unit fromUnit, Unit toUnit) noexcept {
223 return value * getConversionFactor(fromUnit, toUnit);
224 }
225
233 static double convertToEdaUnits(double value, std::string_view unitStr, EDA_UNITS targetUnits) {
234 Unit fromUnit = parseUnit(unitStr);
235 if (fromUnit == Unit::INVALID) {
236 return value; // No conversion for invalid units
237 }
238
239 Unit toUnit = fromEdaUnits(targetUnits);
240 return convertValue(value, fromUnit, toUnit);
241 }
242
248 static constexpr bool isValidUnit(std::string_view unitStr) noexcept {
249 return parseUnit(unitStr) != Unit::INVALID;
250 }
251
257 static std::optional<UnitInfo> getUnitInfo(Unit unit) noexcept {
258 for (const auto& info : s_unitTable) {
259 if (info.unit == unit) {
260 return info;
261 }
262 }
263 return std::nullopt;
264 }
265};
266
267} // namespace text_eval_units
Unit registry that provides centralized unit string mapping and conversion.
static constexpr Unit parseUnit(std::string_view unitStr) noexcept
Parse a unit string and return the corresponding Unit enum.
static double convertToEdaUnits(double value, std::string_view unitStr, EDA_UNITS targetUnits)
Convert a value with unit string to target EDA_UNITS.
static constexpr bool isValidUnit(std::string_view unitStr) noexcept
Check if a string is a valid unit.
static constexpr std::array< UnitInfo, 15 > s_unitTable
static constexpr std::string_view getUnitString(Unit unit) noexcept
Get the unit string for a given Unit enum.
static std::vector< std::string > getAllUnitStrings()
Get all unit strings in parsing order (longest first)
static constexpr Unit fromEdaUnits(EDA_UNITS edaUnits) noexcept
Convert EDA_UNITS to text evaluator Unit enum.
static std::optional< UnitInfo > getUnitInfo(Unit unit) noexcept
Get unit information for debugging/display purposes.
static constexpr double getConversionFactor(Unit fromUnit, Unit toUnit) noexcept
Get conversion factor from one unit to another.
static constexpr double convertValue(double value, Unit fromUnit, Unit toUnit) noexcept
Convert a value with units to target units.
EDA_UNITS
Definition eda_units.h:48
@ PS_PER_INCH
Definition eda_units.h:59
#define KICOMMON_API
Definition kicommon.h:28
Unit
Enumeration of all supported units in the text evaluation system.