/* $NoKeywords: $ */ /* // // Copyright (c) 1993-2013 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// */ #include "opennurbs.h" #if !defined(ON_COMPILING_OPENNURBS) // This check is included in all opennurbs source .c and .cpp files to insure // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined // and the opennurbs .h files alter what is declared and how it is declared. #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs #endif #include "opennurbs_parse.h" #define ON_UNICODE_QUOTATION_MARK 0x0022 #define ON_WCHAR_QUOTATION_MARK L"\"" #define ON_UNICODE_APOSTROPHE 0x0027 #define ON_WCHAR_APOSTROPHE L"\'" #define ON_UNICODE_LOW_LINE 0x005F #define ON_UNICODE_DEGREE_SYMBOL 0x00B0 #define ON_WCHAR_DEGREE_SYMBOL L"\x00B0" // The unicode masuline ordinal indicator (Spanish) // is often mistakenlyused as a degrees symbol. #define ON_UNICODE_MASCULINE_ORDINAL_INDICATOR 0x00BA #define ON_WCHAR_MASCULINE_ORDINAL_INDICATOR L"\x00BA" #define ON_UNICODE_LATIN_SMALL_LETTER_SHARP_S 0x00DF #define ON_WCHAR_LATIN_SMALL_LETTER_SHARP_S L"\x00DF" #define ON_UNICODE_LATIN_CAPITAL_LETTER_U_WITH_RING_ABOVE 0x016E #define ON_WCHAR_LATIN_CAPITAL_LETTER_U_WITH_RING_ABOVE L"\x016E" #define ON_UNICODE_LATIN_SMALL_LETTER_U_WITH_RING_ABOVE 0x016F #define ON_WCHAR_LATIN_SMALL_LETTER_U_WITH_RING_ABOVE L"\x016F" #define ON_UNICODE_LATIN_CAPITAL_LETTER_SHARP_S 0x1E9E #define ON_UNICODE_GREEK_CAPITAL_LETTER_TAU 0x03A4 #define ON_UNICODE_GREEK_SMALL_LETTER_TAU 0x03C4 #define ON_WCHAR_GREEK_SMALL_LETTER_TAU L"\x03C4" #define ON_RHINO_LOCALE_ID 1 #define ON_INVALID_LOCALE_ID 2 #define ON_CS_CZ_LOCALE_ID ON_Locale::WindowsLCID::cs_CZ_LCID #define ON_DE_DE_LOCALE_ID ON_Locale::WindowsLCID::de_DE_LCID #define ON_EN_CA_LOCALE_ID ON_Locale::WindowsLCID::en_CA_LCID #define ON_EN_US_LOCALE_ID ON_Locale::WindowsLCID::en_US_LCID #define ON_ES_ES_LOCALE_ID ON_Locale::WindowsLCID::es_ES_LCID #define ON_FR_FR_LOCALE_ID ON_Locale::WindowsLCID::fr_FR_LCID #define ON_IT_IT_LOCALE_ID ON_Locale::WindowsLCID::it_IT_LCID #define ON_PL_PL_LOCALE_ID ON_Locale::WindowsLCID::pl_PL_LCID #define ON_PT_PT_LOCALE_ID ON_Locale::WindowsLCID::pt_PT_LCID class ON_UnitName { public: // The size and field alignment of ON_UnitName must exactly match // that of ON_LengthUnitName and ON_AngleUnitName // Microsoft locale id // http://msdn.microsoft.com/en-us/library/ms912047(v=winembedded.10).aspx unsigned int m_locale_id; // ON::LengthUnitSystem or ON::AngleUnitSystem enum value unsigned char m_unit_system; bool m_bIsSingular; bool m_bIsPlural; const wchar_t* m_name; }; class ON_UnitNameEx : public ON_UnitName { public: enum { m_utf32_name_capacity = 24 }; // Simplified name - used for speedy unit name searches. ON__UINT32 m_utf32_name[ON_UnitNameEx::m_utf32_name_capacity]; // null terminated utf-32 encoded lower case simple latin name string. unsigned int m_utf32_name_count; // number of nonzero wchar_t elements in m_name[] array /* Description: Parses m_name and sets the m_utf32_name[] and m_utf32_name_count fields. Returns: Number of elments of m_name that were parsed; 0 indicates failure. Remarks: m_name must contain a character that terminates unit system name parsing. This can be a null, digit, punctuation, aritmetic operator, or a unicode code point <= 0x0020 (0x0020 = space = 32 decimal). */ int SetSimplifiedName(); static int Compare(const ON_UnitNameEx*, const ON_UnitNameEx*); static int Compare_m_utf32_name(const ON_UnitNameEx*, const ON_UnitNameEx*); static int Compare_m_name(const ON_UnitNameEx*, const ON_UnitNameEx*); }; static ON_UnitName si_length_units[] = { ////////////////////////////////////////////////////////////// // // SI length units universal // {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, true, L"mm" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, true, L"cm" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, true, L"m" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, true, L"km" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, true, L"_mm" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, true, L"_cm" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, true, L"_m" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, true, L"_km" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"_millimeters" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"_millimeter" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"_centimeters" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"_centimeter" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"_meters" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"_meter"}, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"_kilometers" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"_kilometer" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"_millimetres" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"_millimetre" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"_centimetres" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"_centimetre" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"_metres" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"_metre" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"_kilometres" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"_kilometre" }, ////////////////////////////////////////////////////////////// // // SI length units cs-* Czech // {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"milimetr" ON_WCHAR_LATIN_SMALL_LETTER_U_WITH_RING_ABOVE }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"milimetry" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"milimetr" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centimetr" ON_WCHAR_LATIN_SMALL_LETTER_U_WITH_RING_ABOVE }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centimetry" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"centimetr" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metr" ON_WCHAR_LATIN_SMALL_LETTER_U_WITH_RING_ABOVE }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metry" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"metr" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilometr" ON_WCHAR_LATIN_SMALL_LETTER_U_WITH_RING_ABOVE }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilometry" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"kilometr" }, ////////////////////////////////////////////////////////////// // // SI length units de-* German // {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, true, L"Millimeter" }, {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, true, L"Zentimeter" }, {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, true, L"Meter" }, {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, true, L"Kilometer" }, // http://mcneel.myjetbrains.com/youtrack/issue/RH-34051 // The words ending in n are not plural forms, they are inflected forms used in complete sentences. // They are included so information copied, possibly automatically, from documents into scripts will parse as expected. {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, true, L"Millimetern" }, {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, true, L"Zentimetern" }, {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, true, L"Metern" }, {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, true, L"Kilometern" }, // http://mcneel.myjetbrains.com/youtrack/issue/RH-34051 // "zm" is not the way German speakers abbreviate zentimeter // NO // {ON_DE_DE_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, true, L"zm" }, ////////////////////////////////////////////////////////////// // // SI length units en-CA (metric Canadian English) // {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"millimetres" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"millimetre" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centimetres" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"centimetre" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metres" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"metre" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilometres" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"kilometre" }, ////////////////////////////////////////////////////////////// // // SI length units en-US (metric American English) // {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"millimeters" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"millimeter" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centimeters" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"centimeter" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"meters" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"meter" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilometers" }, {ON_EN_US_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"kilometer" }, ////////////////////////////////////////////////////////////// // // SI length units es-* Spanish // {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"mil\x00EDmetros" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"mil\x00EDmetro" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"cent\x00EDmetros" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"cent\x00EDmetro" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metros" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"metro" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kil\x00F3metros" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"kil\x00F3metro" }, ////////////////////////////////////////////////////////////// // // SI length units fr-* French // {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"millim\x00E8tres" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"millim\x00E8tre" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centim\x00E8tres" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"centim\x00E8tre" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"m\x00E8tres" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"m\x00E8tre" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilom\x00E8tres" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"kilom\x00E8tre" }, ////////////////////////////////////////////////////////////// // // SI length units it-* Italian // {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"millimetri" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"millimetro" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centimetri" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"centimetro" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metri" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false , L"metro"}, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"chilometri" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"chilometro" }, // it-* abbreviation for chilometri is "km" ////////////////////////////////////////////////////////////// // // SI length units pl-* Polish {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"milimetr" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"milimetr\x00F3w" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"milimetry" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"centymetr" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centymetr\x00F3w" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"centymetry" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"metr" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metr\x00F3w" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metry" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"kilometr" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilometr\x00F3w" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"kilometry" }, ////////////////////////////////////////////////////////////// // // SI length units pt-* Portuguese {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), false, true, L"mil\x00EDmetros" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Millimeters), true, false, L"mil\x00EDmetro" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), false, true, L"cent\x00EDmetros" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Centimeters), true, false, L"cent\x00EDmetro" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), false, true, L"metros" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Meters), true, false, L"metro" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), false, true, L"quil\x00F4metros" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, false, L"quil\x00F4metro" }, // "qm" uilometro is abbreviated in Brazil and Portugual // NO // {ON_PT_PT_LOCALE_ID, static_cast(ON::LengthUnitSystem::Kilometers), true, true, L"qm" }, }; static ON_UnitName en_US_customary_length_units[] = { ////////////////////////////////////////////////////////////// // // United States customary units (Rhino - all locales) // // All conversions to meters are exact. // microinch = 2.54e-8 meters (1.0e-6 inches) // mil = 2.54e-5 meters (0.001 inches) // inch = 0.0254 meters (1/12 foot) // foot = 0.3048 meters (12 inches) // yard = 0.9144 meters (3 feet, 36 inches) // mile = 1609.344 meters (5280 feet) // // United States customary units are supported in en-US for two reasons. // 1) There is a internationally accepted definition of US customary // lengths in terms of meters. The international yard and pound // agreement of July 1, 1959 defined one yard to be exactly // 0.9144 meters which implies one inch is exactly 0.0254 meters. // http://www.ngs.noaa.gov/PUBS_LIB/FedRegister/FRdoc59-5442.pdf // 2) These customary units are currently and widely used in the // United States. // // United States customary units are not supported in any other // language or culture because there are no internationally // accepted and commonly used definitions in terms of meters // that match the ones used in the United States and the units // are not commonly used in precise digital models. // // For an inlking of the peril of assuming a length unit in // Czech, French, Italian, Portuguese or Spanish that linguistically // translates to English "inch", "foot", or "mile" has the same physical // length as the "United States customary unit", see the references below. // http://en.wikipedia.org/wiki/Foot_(unit) // http://en.wikipedia.org/wiki/German_obsolete_units_of_measurement // http://en.wikipedia.org/wiki/Spanish_customary_units // http://en.wikipedia.org/wiki/Portuguese_customary_units // http://en.wikipedia.org/wiki/Units_of_measurement_in_France // http://www.convert-me.com/en/convert/length // http://www.wordreference.com/czen/palec // http://www.onlineunitconversion.com/braccio.Italy_to_miglio.html // // All conversions to meters and other US customary units are exact. // // 1 microinch = 2.54e-8 meters (1.0e-6 inches) {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Microinches), false, true, L"microinches" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Microinches), true, false, L"microinch" }, // 1 mil = 2.54e-5 meters (0.001 inches) {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Mils), false, true, L"mils" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Mils), true, false, L"mil" }, // 1 inch = 0.0254 meters = 1/12 foot {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), false, true, L"inches" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), true, false, L"inch" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), false, true, L"ins" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), true, true, L"in" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), true, true, ON_WCHAR_QUOTATION_MARK }, // 1 foot = 0.3048 meters = 12 inches {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), false, true, L"feet" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), true, false, L"foot" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), true, true, L"ft" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), true, true, ON_WCHAR_APOSTROPHE }, // 1 yard = 0.9144 meters = 3 feet = 36 inches {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), false, true, L"yards" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), true, false, L"yard" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), false, true, L"yds" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), true, true, L"yd" }, // 1 US statute mile = 1609.34 meters = 5280 feet {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Miles), false, true, L"miles" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Miles), true, false, L"mile" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Miles), true, true, L"mi" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Microinches), true, true, L"_microinches" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Microinches), true, true, L"_microinch" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Mils), false, true, L"_mils" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Mils), true, false, L"_mil" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), false, true, L"_inches" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), true, false, L"_inch" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), false, true, L"_ins" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Inches), true, true, L"_in" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), false, true, L"_feet" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), true, false, L"_foot" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Feet), true, true, L"_ft" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), false, true, L"_yards" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), true, false, L"_yard" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), false, true, L"_yds" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Yards), true, true, L"_yd" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Miles), false, true, L"_miles" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Miles), true, false, L"_mile" }, {ON_RHINO_LOCALE_ID, static_cast(ON::LengthUnitSystem::Miles), true, true, L"_mi" }, }; static ON_UnitName angle_no_units[] = { // These entries prevent parsing the strings unless an // entry for a locale explicitly inludes the string and // the parsing prefered local id matches exactly. // The purpose is to prevent incorrectly parsing strings // the define different unit systems in different // locales. // Many strings that begin with "g" can mean degrees // in one locale and gradians in another locale. {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"g" }, {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"gs" }, {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"gc" }, {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"gd" }, {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"grad" }, {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"grads" }, // "s" could mean degrees in Czech or Polish and seconds in English. {ON_INVALID_LOCALE_ID, static_cast(ON::AngleUnitSystem::None), true, true, L"s" }, }; static ON_UnitName angle_radian_units[] = { ////////////////////////////////////////////////////////////// // // radian units universal // {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radians" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radian" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"rads" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"rad" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, true, L"r" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"_radians" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"_radian" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"_rads" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"_rad" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, true, L"_r" }, ////////////////////////////////////////////////////////////// // // radian units cs-* Czech // {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radi\x00E1ny" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radi\x00E1n" }, ////////////////////////////////////////////////////////////// // // radian units en-* (radians English) // {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radians" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radian" }, ////////////////////////////////////////////////////////////// // // radian units de-* German // {ON_DE_DE_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, true, L"Bogenma" ON_WCHAR_LATIN_SMALL_LETTER_SHARP_S }, ////////////////////////////////////////////////////////////// // // radian units es-* Spanish // {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radianes" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radi\x00E1n" }, ////////////////////////////////////////////////////////////// // // radian units fr-* French // {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radians" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radian" }, ////////////////////////////////////////////////////////////// // // radian units it-* Italian // {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radianti" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radiante" }, ////////////////////////////////////////////////////////////// // // radian units pl-* Polish {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radiany" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radian" }, ////////////////////////////////////////////////////////////// // // radian units pt-* Portuguese {ON_PT_PT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), false, true, L"radians" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Radians), true, false, L"radian" }, }; static ON_UnitName angle_degree_units[] = { ////////////////////////////////////////////////////////////// // // arc degree unit abbreviations (Rhino - all locales) // {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, ON_WCHAR_DEGREE_SYMBOL }, // The unicode masuline ordinal indicator (Spanish) // is often mistakenlyused as a degrees symbol. {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, ON_WCHAR_MASCULINE_ORDINAL_INDICATOR }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"degrees" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"degree" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"degs" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"deg" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"d" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"_degrees" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"_degree" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"_degs" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"_deg" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"_d" }, ////////////////////////////////////////////////////////////// // // arc degree units cs-* (Czech) // {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"stupn\x011B" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"stupe\x0148" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"stup" }, ////////////////////////////////////////////////////////////// // // arc degree units en-* (English) // {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"degrees" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"degree" }, ////////////////////////////////////////////////////////////// // // arc degree units de-* (German) // {ON_DE_DE_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"Grad" }, ////////////////////////////////////////////////////////////// // // arc degree units es-* (Spanish) // {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"grados" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"grado" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"grads" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"grad" }, ////////////////////////////////////////////////////////////// // // arc degree units fr-* (French) // {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"degr\x00E9s" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"degr\x00E9" }, ////////////////////////////////////////////////////////////// // // arc degree units it-* (Italian) // {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"gradisessagesimali" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"gradosessagesimale" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"gradi" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"grado" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"gs" }, ////////////////////////////////////////////////////////////// // // arc degree units pl-* Polish {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"stopnie" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"stopie\x0144" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, true, L"stop" }, ////////////////////////////////////////////////////////////// // // arc degree units pt-* (Portuguese) {ON_PT_PT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), false, true, L"graus" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Degrees), true, false, L"grau" }, }; static ON_UnitName angle_minute_units[] = { ////////////////////////////////////////////////////////////// // // arc minute unit abbreviations (Rhino - all locales) // {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, true, ON_WCHAR_APOSTROPHE }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), false, true, L"mins" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, false, L"min" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, true, L"m" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), false, true, L"_minutes" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, false, L"_minute" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), false, true, L"_mins" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, false, L"_min" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, true, L"_m" }, ////////////////////////////////////////////////////////////// // // arc minute units cs-* (Czech) // ////////////////////////////////////////////////////////////// // // arc minute units en-* (English) // {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), false, true, L"minutes" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Minutes), true, false, L"minute" }, ////////////////////////////////////////////////////////////// // // arc minute units de-* (German) // ////////////////////////////////////////////////////////////// // // arc minute units es-* (Spanish) // ////////////////////////////////////////////////////////////// // // arc minute units fr-* (French) // ////////////////////////////////////////////////////////////// // // arc minute units it-* (Italian) // ////////////////////////////////////////////////////////////// // // arc minute units pt-* (Portuguese) }; static ON_UnitName angle_second_units[] = { ////////////////////////////////////////////////////////////// // // arc second unit abbreviations (Rhino - all locales) // {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, true, ON_WCHAR_QUOTATION_MARK }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), false, true, L"seconds" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, false, L"second" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), false, true, L"secs" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, false, L"sec" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), false, true, L"_seconds" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, false, L"_second" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), false, true, L"_secs" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, false, L"_sec" }, ////////////////////////////////////////////////////////////// // // arc second units cs-* (Czech) // ////////////////////////////////////////////////////////////// // // arc second units en-* (English) // {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), false, true, L"seconds" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, false, L"second" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Seconds), true, true, L"s" }, ////////////////////////////////////////////////////////////// // // arc second units de-* (German) // ////////////////////////////////////////////////////////////// // // arc second units es-* (Spanish) // ////////////////////////////////////////////////////////////// // // arc second units fr-* (French) // ////////////////////////////////////////////////////////////// // // arc second units it-* (Italian) // ////////////////////////////////////////////////////////////// // // arc second units pt-* (Portuguese) }; static ON_UnitName angle_turn_units[] = { ////////////////////////////////////////////////////////////// // // turn unit universal // {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), true, true, ON_WCHAR_GREEK_SMALL_LETTER_TAU }, // unicode small tau symbol {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), false, true, L"turns" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), true, false, L"turn" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), true, true, L"t" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), true, true, L"_t" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), false, true, L"_turns" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), true, false, L"_turn" }, ////////////////////////////////////////////////////////////// // // turn units cs-* Czech // ////////////////////////////////////////////////////////////// // // turn units en-* English // {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), false, true, L"turns" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Turns), true, false, L"turn" }, ////////////////////////////////////////////////////////////// // // turn units de-* German // ////////////////////////////////////////////////////////////// // // turn units es-* Spanish // ////////////////////////////////////////////////////////////// // // turn units fr-* French // ////////////////////////////////////////////////////////////// // // turn units it-* Italian // ////////////////////////////////////////////////////////////// // // turn units pt-* Portuguese }; static ON_UnitName angle_gradian_units[] = { ////////////////////////////////////////////////////////////// // // gradian units universal // {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gons" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gon" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"_gons" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"_gon" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"_gradians" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"_gradian" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"_grads" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"_grad" }, {ON_RHINO_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"_g" }, ////////////////////////////////////////////////////////////// // // gradian units cs-* Czech // {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gradi\x00E1ny" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"grad" }, {ON_CS_CZ_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"g" }, ////////////////////////////////////////////////////////////// // // gradian units en-* English // {ON_EN_CA_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gradians" }, {ON_EN_CA_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gradian" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gradians" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gradian" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"grads" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"grad" }, {ON_EN_US_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"g" }, ////////////////////////////////////////////////////////////// // // gradian units de-* German // // German uses the universal "gon" which is in ON_RHINO_LOCALE_ID ////////////////////////////////////////////////////////////// // // gradian units es-* Spanish // // https://es.wikipedia.org/wiki/Grado_centesimal // http://blog.utp.edu.co/adriamec/files/2012/10/NTC1000.pdf (document page 8, PDF page 11) {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gradianes" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gradi\x00E1n" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gons" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gon" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gradoscent" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gradcent" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gonios" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gonio" }, {ON_ES_ES_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"gd" }, ////////////////////////////////////////////////////////////// // // gradian units fr-* French // {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"grades" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"grade" }, {ON_FR_FR_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"g" }, ////////////////////////////////////////////////////////////// // // gradian units it-* Italian // {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"gradicent" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"gradocent" }, {ON_IT_IT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"gc" }, ////////////////////////////////////////////////////////////// // // gradian units pl-* Polish {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"grads" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"grad" }, {ON_PL_PL_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, true, L"g" }, ////////////////////////////////////////////////////////////// // // gradian units pt-* Portuguese // {ON_PT_PT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), false, true, L"grads" }, {ON_PT_PT_LOCALE_ID, static_cast(ON::AngleUnitSystem::Gradians), true, false, L"grad" }, }; static unsigned int MapPreferedLocaleId( unsigned int prefered_locale_id ) { switch (prefered_locale_id) { case ON_Locale::WindowsLCID::es_ES_tradnl_LCID: prefered_locale_id = ON_Locale::WindowsLCID::es_ES_LCID; break; } return prefered_locale_id; } static int CompareNullPointers(const void* a, const void* b) { if ( 0 == a || 0 == b ) { if ( 0 != b ) return -1; if ( 0 != a ) return 1; } return 0; } int ON_UnitNameEx::Compare(const ON_UnitNameEx* a, const ON_UnitNameEx* b) { int rc = Compare_m_utf32_name(a,b); if ( 0 == rc && 0 != a && 0 != b ) { if ( a->m_locale_id < b->m_locale_id ) rc = -1; else if ( a->m_locale_id > b->m_locale_id ) rc = 1; else rc = Compare_m_name(a,b); } return rc; } int ON_UnitNameEx::Compare_m_utf32_name(const ON_UnitNameEx* a, const ON_UnitNameEx* b) { int rc = CompareNullPointers(a,b); if ( 0 != rc || 0 == a ) return rc; if ( a->m_utf32_name_count < b->m_utf32_name_count ) return -1; if ( a->m_utf32_name_count > b->m_utf32_name_count ) return 1; ON__UINT32 x, y; const unsigned int capacity = ON_UnitNameEx::m_utf32_name_capacity; unsigned int i; for ( i = 0; i < capacity; i++ ) { x = a->m_utf32_name[i]; y = b->m_utf32_name[i]; if ( x < y ) return -1; if ( y < x ) return 1; if ( 0 == x ) break; } return 0; } int ON_UnitNameEx::Compare_m_name(const ON_UnitNameEx* a, const ON_UnitNameEx* b) { int rc = CompareNullPointers(a,b); if ( 0 != rc || 0 == a ) return rc; rc = CompareNullPointers(a->m_name,b->m_name); if ( 0 != rc || 0 == a->m_name ) return rc; wchar_t x, y; unsigned int i = 0; for(;;) { x = a->m_name[i]; y = b->m_name[i]; if ( x < y ) return -1; if ( y < x ) return 1; if ( 0 == x ) break; i++; } return 0; } static ON__UINT32 ON_ToLower( ON__UINT32 c ) { // This is a specialized and fast version that converts selected // unicode capital latin letter code points to the corresponding // unicode latin small letter code points. It is designed to be // used in code that has to quickly parse common unit names // in English, Spanish, French, German, Protuguese and Czech. // If other languages need to be supported, this funcition // may need to be enhanced. // // In many situations, "to lower" requires more context than a single // unicode code point. If those cases need to be handled correctly, // then this function will need to be discarded. // // The reason this function exists is that there is not a robust // C library function that does "to lower" on wchar_t strings // that works on Microsoft's, Apple's, Google's or Gnu's // compilers. There are solutions, but many depend on other // app state variables that define an app/machine locale. // This meeans the result is not "predictably consistent". if ( c < 'A' ) return c; if ( c <= 'Z' ) return c + 0x0020; // A to a, .... Z to z if ( c < 0x00C0 ) return c; if ( c <= 0x00DE ) { if ( 0x00D7 == c ) return c; // multiplication sign return c + 0x0020; } if ( c < 0x0100 ) return c; if ( c <= 0x0137 ) { // add 1 if c is even c |= 0x0001; return c; } if ( c < 0x0139 ) return c; if ( c < 0x0148 ) { if ( 0 != (c % 2) ) c++; return c; } if ( c < 0x014A ) return c; if ( c < 0x0177 ) { // add 1 if c is odd c |= 0x0001; return c; } if ( c < 0x0179 ) return c; if ( c < 0x017E ) { if ( 0 != (c % 2) ) c++; return c; } if ( c < ON_UNICODE_LATIN_CAPITAL_LETTER_SHARP_S ) { // NOTE: // This skips some "obvious" to lower conversions, but none // of these conversions are needed for common unit // names in English, Spanish, French, German, Protuguese // or Czech. return c; } switch(c) { case ON_UNICODE_GREEK_CAPITAL_LETTER_TAU: // symbol for angle "turns" c = ON_UNICODE_GREEK_SMALL_LETTER_TAU; break; case ON_UNICODE_LATIN_CAPITAL_LETTER_SHARP_S: c = ON_UNICODE_LATIN_SMALL_LETTER_SHARP_S; break; } return c; } static ON__UINT32 ON_ToLatinAtoZ( ON__UINT32 c ) { // This is a specialized and fast version that converts selected // unicode code points whose glyph is a latin letter A to Z with a // diacritical mark to the corresponding latin A to Z letter. // It also converts sharp s (eszett) to latin letter S and // greek tau to to latin letter T. // // This code is designed to be used efficently parse common unit // names in English, Spanish, French, German, Protuguese and Czech. // If other languages need to be supported, this function will need // to be enhanced, redone, or removed. The unit names being parsed // by this code are often input on devices, like English language // keyboards, where it is not convenient for the user to type a // letter or symbol in the language being used. // // Discarding diacritical marks is a risky approach. Specifically, // this function cannot be used in any context where different // relevant words will be mapped to the same "A to Z" version. if ( c < 0x00C0 ) return c; if ( c < 0x0100 ) { if ( c >= 0x00C0 && c <= 0x00C5 ) c = 'A'; // capital letter A with grave, acute, circumflex, tilde, diaeresis, ring above, else if ( c >= 0x00C8 && c <= 0x00CB ) c = 'E'; // capital letter E with grave, acute, circumflex, diaeresis, else if ( c >= 0x00CC && c <= 0x00CF ) c = 'I'; // capital letter I with grave, acute, circumflex, diaeresis, else if ( c >= 0x00D2 && c <= 0x00D6 ) c = 'O'; // capital letter O with grave, acute, circumflex, tilde, diaeresis, else if ( c >= 0x00D9 && c <= 0x00DC ) c = 'U'; // capital letter U with grave, acute, circumflex, diaeresis, else if ( c >= 0x00E0 && c <= 0x00E5 ) c = 'a'; // small letter a with grave, acute, circumflex, tilde, diaeresis, ring above, else if ( c == 00E7 ) c = 'c'; // small letter c with dedilla else if ( c >= 0x00E8 && c <= 0x00EB ) c = 'e'; // small letter e with grave, acute, circumflex, tilde, diaeresis, ring above, else if ( c >= 0x00EC && c <= 0x00EF ) c = 'i'; // small letter i with grave, acute, circumflex, tilde, diaeresis, ring above, else if ( c == 0x00F1 ) c = 'n'; // small letter n with tilde else if ( c >= 0x00F2 && c <= 0x00F6 ) c = 'o'; // small letter o with grave, acute, circumflex, tilde, diaeresis, else if ( c == 0x00F8 ) c = 'o'; // small letter o with stroke else if ( c >= 0x00F9 && c <= 0x00FC ) c = 'u'; // small letter u with grave, acute, circumflex, tilde, diaeresis, else if ( c == 0x00FD ) c = 'y'; // small letter y with acute else if ( c == 0x00FF ) c = 'y'; // small letter y with diaeresis else { switch (c) { case 0x00D0: // capital letter Eth c = 'D'; break; case 0x00D1: // capital letter N with tilde c = 'N'; break; case 0x00D8: // capital letter O with stroke c = 'O'; break; case ON_UNICODE_LATIN_SMALL_LETTER_SHARP_S: // small sharp s (German eszet) c = 's'; break; case 0x00C7: // capital letter C with cedilla c = 'C'; break; case 0x00DD: // capital letter Y with acute c = 'Y'; break; case 0x00E7: // small letter c with cedilla c = 'c'; break; case 0x00F0: // small letter Eth c = 'd'; break; } } } else if ( c < 0x0200 ) { if ( c >= 0x0100 && c <= 0x0105 ) c = ((0 != (1&c)) ? 'a' : 'A'); // odds -> small A else if ( c >= 0x0106 && c <= 0x010D ) c = ((0 != (1&c)) ? 'c' : 'C'); // odds -> small C else if ( c >= 0x010E && c <= 0x0111 ) c = ((0 != (1&c)) ? 'd' : 'D'); // odds -> small D else if ( c >= 0x0112 && c <= 0x011B ) c = ((0 != (1&c)) ? 'e' : 'E'); // odds -> small E else if ( c >= 0x011C && c <= 0x0123 ) c = ((0 != (1&c)) ? 'g' : 'G'); // odds -> small G else if ( c >= 0x0124 && c <= 0x0127 ) c = ((0 != (1&c)) ? 'h' : 'H'); // odds -> small H else if ( c >= 0x0128 && c <= 0x0131 ) c = ((0 != (1&c)) ? 'i' : 'I'); // odds -> small I else if ( c >= 0x0134 && c <= 0x0135 ) c = ((0 != (1&c)) ? 'j' : 'J'); // odds -> small J else if ( c >= 0x0136 && c <= 0x0137 ) c = ((0 != (1&c)) ? 'k' : 'K'); // odds -> small K else if ( c == 0x0138 ) c = 'k'; // small kra else if ( c >= 0x0139 && c <= 0x0142 ) c = ((0 != (1&c)) ? 'L' : 'l'); // odds -> capital L else if ( c >= 0x0143 && c <= 0x0148 ) c = ((0 != (1&c)) ? 'N' : 'n'); // odds -> capital N else if ( c == 0x0149 ) c = 'n'; //small n preceded by apostrophe else if ( c >= 0x014C && c <= 0x0151 ) c = ((0 != (1&c)) ? 'o' : 'O'); // odds -> small O else if ( c >= 0x0154 && c <= 0x0159 ) c = ((0 != (1&c)) ? 'r' : 'R'); // odds -> small R else if ( c >= 0x015A && c <= 0x0161 ) c = ((0 != (1&c)) ? 's' : 'S'); // odds -> small S else if ( c >= 0x0162 && c <= 0x0167 ) c = ((0 != (1&c)) ? 't' : 'T'); // odds -> small t else if ( c >= 0x0168 && c <= 0x0173 ) c = ((0 != (1&c)) ? 'u' : 'U'); // odds -> small u else if ( c >= 0x0174 && c <= 0x0175 ) c = ((0 != (1&c)) ? 'w' : 'W'); // odds -> small w else if ( c >= 0x0176 && c <= 0x0178 ) c = ((0 != (1&c)) ? 'y' : 'Y'); // odds -> small y else if ( c >= 0x0179 && c <= 0x017E ) c = ((0 != (1&c)) ? 'z' : 'Z'); // odds -> capital Z } else { switch (c) { case ON_UNICODE_GREEK_CAPITAL_LETTER_TAU: // (angle turn units) c = 'T'; break; case ON_UNICODE_GREEK_SMALL_LETTER_TAU: // (angle turn units) c = 't'; break; case ON_UNICODE_LATIN_CAPITAL_LETTER_SHARP_S: // (German eszett) c = 'S'; } } return c; } /* Description: This function is designed to be used to map common unit names and abbreviations in Czech, English, French, German, Spanish and Portuguese to a lower case latin name that has unicode code points 'a' to 'z' that can be used in code that parses input streams that specify angles, lengths or point coordinates. Parameters: name - [in] String to test to see if it begins with a common unit name or abbreviation in Czech, English, French, German, Italian, Portuguese or Spanish. utf32_small_simple_name - [out] A buffer where a null termintated UTF-32 encoded simplified small letter version of the input unit name is returned. utf32_small_simple_name_capacity - [in] Number of elements that can be used in utf32_small_simple_name[] Returns: 0: name was not a unit recognized by this function. >0: number of elements of name[] that were parsed as a unit name or abbreviation. Remarks: This code is used to quickly parse optional embedded unit names, abreviations in input streams that specify angles, lengths, points in cartesian coordinates, and points in polar coordinates. The unit systems in the strings may be different from the language the applications user interface is using or the unit names may be entered on a device, like and english language keyboard, that does not provide easy access to latin letters with diacritical marks. If it becomes necessary to correctly handle languages like Russian, Greek, Arabic, Hebrew, Asian languages or anything else that does not use latin-esque letters with diacritical marks, then this code will be useless and must be discarded. */ static unsigned int ON_GetSmallSimpleUnitsName( const wchar_t* name, ON__UINT32* utf32_small_simple_name, size_t utf32_small_simple_name_capacity ) { ON_UnicodeErrorParameters e = {0}; int decode_count; ON__UINT32 c, lower_c, simple_c; if ( 0 == utf32_small_simple_name || utf32_small_simple_name_capacity <= 0 ) { // failure return 0; } if ( utf32_small_simple_name_capacity > 1 ) { // check for common single glyph symbols that are used // when specify length and angle units switch(name[0]) { case ON_UNICODE_QUOTATION_MARK: // quote (inches, arc seconds) case ON_UNICODE_APOSTROPHE: // apostophe (feet, arc minutes) case ON_UNICODE_DEGREE_SYMBOL: // degree symbol (arc degrees) case ON_UNICODE_GREEK_SMALL_LETTER_TAU: // small tau (turns) utf32_small_simple_name[0] = (ON__UINT32)(name[0]); utf32_small_simple_name[1] = 0; return 1; case ON_UNICODE_GREEK_CAPITAL_LETTER_TAU: // capital tau (turns) // This is done so strings that have passed through // a "toupper" converter will parse correctly. utf32_small_simple_name[0] = (ON__UINT32)ON_UNICODE_GREEK_SMALL_LETTER_TAU; utf32_small_simple_name[1] = 0; return 1; case ON_UNICODE_MASCULINE_ORDINAL_INDICATOR: // The unicode masuline ordinal indicator (Spanish) // is often mistakenlyused as a degrees symbol. utf32_small_simple_name[0] = ON_UNICODE_DEGREE_SYMBOL; utf32_small_simple_name[1] = 0; return 1; } } bool bLeadingUnderbar = false; utf32_small_simple_name[0] = 0; // return quickly when beginning code point cannot possibly // be a unit. if ( name[0] >= 0 && name[0] < 'A' ) { return 0; } if ( name[0] > 'Z' && name[0] < 'a' ) { // leading underbar is allowed if ( ON_UNICODE_LOW_LINE != name[0] ) return 0; if ( name[1] >= 0 && name[1] < 'A' ) return 0; if ( name[1] > 'Z' && name[1] < 'a' ) return 0; if ( name[1] > 'z' && name[1] < 0x80 ) return 0; bLeadingUnderbar = true; } if ( name[0] > 'z' && name[0] < 0x80 ) { return 0; } size_t count = 0; int name_index = 0; while ( count < utf32_small_simple_name_capacity && 0 != name[name_index] ) { e.m_error_status = 0; c = 0xFFFFFFFF; if ( name[name_index] <= 127 && name[name_index] >= 0 ) { // The code point value for all UTF-* encodings map // values from 0 to 127 (ASCII) to the same code point // value. These values are common and this special case // handling speeds up parsing. c = (ON__UINT32)(name[name_index]); decode_count = 1; } else { switch(sizeof(wchar_t)) { case 1: // assume name is UTF-8 encoded { int name_count = name_index+1; while( 0 != name[name_count] && 0 != (name[name_count] & 0x80) && name_count < name_index+6 ) name_count++; decode_count = ON_DecodeUTF8((const char*)(name+name_index),name_count-name_index,&e,&c); } break; case 2: // assume name is UTF-16 encoded decode_count = ON_DecodeUTF16((const ON__UINT16*)(name+name_index),2,&e,&c); break; case 4: // assume name is UTF-32 encoded c = (ON__UINT32)(name[name_index]); decode_count = 1; break; default: // unsupported wchar_t size decode_count = 0; break; } } if ( decode_count < 1 || !ON_IsValidUnicodeCodePoint(c) ) { count = 0; break; } lower_c = ON_ToLower(c); simple_c = ON_ToLatinAtoZ(lower_c); if ( (simple_c <= 0x40) || (simple_c >= 0x5B && simple_c <= 0x60) || (simple_c >= 0x7B && simple_c <= 0xB4) || (simple_c >= 0xB6 && simple_c <= 0xBF) || (0xD7 == simple_c) || (0xF7 == simple_c) ) { // This character terminates parsing unless it is a leading underbar. if ( count != 0 || !bLeadingUnderbar || ON_UNICODE_LOW_LINE != simple_c ) break; } name_index += decode_count; utf32_small_simple_name[count++] = simple_c; } if ( count >= utf32_small_simple_name_capacity ) count = 0; utf32_small_simple_name[count] = 0; return ((count > 0 && name_index > 0) ? name_index : 0); } int ON_UnitNameEx::SetSimplifiedName() { const unsigned int capacity = ON_UnitNameEx::m_utf32_name_capacity; m_utf32_name[capacity-1] = 0; const int name_index = ON_GetSmallSimpleUnitsName(m_name,m_utf32_name,capacity); unsigned int count = 0; if ( name_index > 0 && 0 != m_utf32_name[0] && 0 == m_utf32_name[capacity-1] ) { while ( 0 != m_utf32_name[count] ) count++; } if ( count > 0 && count < capacity && 0 == m_utf32_name[count] && 0 != m_utf32_name[count-1] ) { m_utf32_name_count = count; } else { m_utf32_name_count = 0; } for ( count = m_utf32_name_count; count < capacity; count++ ) m_utf32_name[count] = 0; return (count > 0 && name_index > 0) ? name_index : 0; } class ON_UnitSystemNameCache { public: // m_unit_list[] has m_unit_list_count elements sorted // by ON_UnitNameEx.m_utf32_name_count (shortest first) // and then by ON_UnitNameEx.m_utf32_name const ON_UnitNameEx* m_unit_list; unsigned int m_unit_list_count; ON_2dex m_unit_index[ON_UnitNameEx::m_utf32_name_capacity]; }; static bool GetUnitSystemNameCache( unsigned int (*GetUnitDictionary)(size_t,ON_UnitName*,ON_UnitNameEx*,bool), bool bIncludeInvalidLocaleIdNames, ON_UnitSystemNameCache& cache ) { unsigned int i; const unsigned int utf32_name_capacity = ON_UnitNameEx::m_utf32_name_capacity; cache.m_unit_list = 0; cache.m_unit_list_count = 0; for ( i = 0; i < utf32_name_capacity; i++ ) { cache.m_unit_index[i].i = 0; cache.m_unit_index[i].j = 0; } // make a list unsigned int capacity = GetUnitDictionary(0,0,0,bIncludeInvalidLocaleIdNames); if ( capacity <= 0 ) return false; // Dale Lear September 16, 2016 // https://mcneel.myjetbrains.com/youtrack/issue/RH-28754 // This allocation appears as a leak but it is not. // This pointer is allocated once when needed, saved as cache.m_unit_list, // and is used for the lifetime of the application. ON_UnitNameEx* unit_list = new (std::nothrow) ON_UnitNameEx[capacity]; if ( nullptr == unit_list ) return false; capacity = GetUnitDictionary(capacity,0,unit_list,bIncludeInvalidLocaleIdNames); if ( capacity <= 0 ) { delete[] unit_list; return false; } // Sort the returned list ON_qsort( unit_list, capacity, sizeof(unit_list[0]), (int (*)(const void*,const void*))ON_UnitNameEx::Compare ); // Cull duplicates and set m_name = 0; unit_list[0].m_name = 0; unsigned int count = 0; for ( i = count+1; i < capacity; i++ ) { unit_list[i].m_name = 0; if ( 0 == ON_UnitNameEx::Compare_m_utf32_name(unit_list+count,unit_list+i) && unit_list[count].m_locale_id == unit_list[i].m_locale_id ) { continue; } count++; if (count < i ) { unit_list[count] = unit_list[i]; } } count++; // The array length_unit_list[] is sorted so the value of // length_unit_list[].m_utf32_name_count increases. // Use that fact to build an index based on the value of // length_unit_list[].m_utf32_name_count so searches can // easily be restriced to the region of length_unit_list[] // where a possible match exists. for ( i = 0; i < count; i++ ) { cache.m_unit_index[unit_list[i].m_utf32_name_count].i = (int)i; while(i+1 < count && unit_list[i].m_utf32_name_count == unit_list[i+1].m_utf32_name_count ) i++; cache.m_unit_index[unit_list[i].m_utf32_name_count].j = (int)(i+1); } cache.m_unit_list = unit_list; if ( 0 != cache.m_unit_list ) cache.m_unit_list_count = count; return (cache.m_unit_list_count > 0); } static unsigned char UnitSystemEnumValue( const ON_UnitSystemNameCache& cache, unsigned int prefered_locale_id, const ON_UnitNameEx* usname ) { prefered_locale_id = MapPreferedLocaleId(prefered_locale_id); if ( 0 == usname || usname->m_utf32_name_count <= 0 || usname->m_utf32_name_count >= ON_UnitNameEx::m_utf32_name_capacity || 0 == usname->m_utf32_name[0] || 0 != usname->m_utf32_name[ON_UnitNameEx::m_utf32_name_capacity-1] ) { return 0; } if ( 0 == cache.m_unit_list || cache.m_unit_list_count <= 0 ) { return 0; } ON_2dex range = cache.m_unit_index[usname->m_utf32_name_count]; // All m_utf32_name entries in s_length_unit_list[range.i,...,range.j-1] // have the same length as usname->m_utf32_name[] and they are sorted by // m_utf32_name. Do a binary search on m_utf32_name after checking // that the first character indicates a match may exist. if ( range.i < range.j && usname->m_utf32_name[0] >= cache.m_unit_list[range.i].m_utf32_name[0] && usname->m_utf32_name[0] <= cache.m_unit_list[range.j-1].m_utf32_name[0] ) { // binary search on m_utf32_name[] value do { int k = (range.i+range.j)/2; int rc = ON_UnitNameEx::Compare_m_utf32_name(usname,cache.m_unit_list+k); if (rc < 0) range.j = k; else if (rc > 0) range.i = k+1; else { // string matches - make sure the locale id is valid if ( prefered_locale_id == cache.m_unit_list[k].m_locale_id ) return cache.m_unit_list[k].m_unit_system; unsigned int common_angle_unit_system = cache.m_unit_list[k].m_unit_system; int k0 = k; while ( k0 > range.i && 0 == ON_UnitNameEx::Compare_m_utf32_name(usname,cache.m_unit_list+(k0-1)) ) { k0--; if ( prefered_locale_id == cache.m_unit_list[k0].m_locale_id ) return cache.m_unit_list[k0].m_unit_system; if ( common_angle_unit_system != cache.m_unit_list[k0].m_unit_system ) common_angle_unit_system = 0; } int k1 = k+1; while ( k1 < range.j && 0 == ON_UnitNameEx::Compare_m_utf32_name(usname,cache.m_unit_list+k1) ) { if ( prefered_locale_id == cache.m_unit_list[k1].m_locale_id ) return cache.m_unit_list[k1].m_unit_system; if ( common_angle_unit_system != cache.m_unit_list[k1].m_unit_system ) common_angle_unit_system = 0; k1++; } // All matching strings specify the same unit system so // we don't care about locale id. if ( common_angle_unit_system != 0 ) { return cache.m_unit_list[k].m_unit_system; } if ( k0+1 == k1 ) { // There is a single entry for this string so // we don't care about locale id. return cache.m_unit_list[k].m_unit_system; } // If we get this far, there are 2 or more strings that // match usname and none of these exactly match the locale // id. for ( k = k0; k < k1; k++ ) { if ( ON_RHINO_LOCALE_ID == cache.m_unit_list[k].m_locale_id ) return cache.m_unit_list[k].m_unit_system; // "universal" string if ( ON_INVALID_LOCALE_ID == cache.m_unit_list[k].m_locale_id ) return 0; // this string requires an exact locale id match // Check for a language match; i.e., if cache.m_unit_list[] is // is for locale en-US and the prefered_locale_id is en-UK, // then use the en-US entry. The "language" part of a locale id // is encoded in the low byte of the locale id. if ( (0xFF & prefered_locale_id) == (0xFF & cache.m_unit_list[k].m_locale_id) ) { // the language part of the local matched return cache.m_unit_list[k].m_unit_system; } } return 0; } } while ( range.i < range.j ); } return 0; } /////////////////////////////////////////////////////////////////////////////// // // Length unit names // /* length_unit_system - [out]] If name is parsed as a length unit system name, then *length_unit_system is set to the corresponding length unit system. If name is not parsed, then *length_unit_system is set to ON::LengthUnitSystem::None. */ unsigned int GetLengthUnitList( size_t length_unit_list_capacity, ON_UnitName* length_unit_list, ON_UnitNameEx* length_unit_ex_list, bool bIncludeInvalidLocaleIdNames ) { size_t si_length_units_count = sizeof(si_length_units)/sizeof(si_length_units[0]); size_t en_US_customary_length_units_count = sizeof(en_US_customary_length_units)/sizeof(en_US_customary_length_units[0]); size_t capacity = si_length_units_count + en_US_customary_length_units_count; if ( 0 == length_unit_list_capacity && 0 == length_unit_list && 0 == length_unit_ex_list ) { return (unsigned int)capacity; } if ( (0 == length_unit_list && 0 == length_unit_ex_list) || length_unit_list_capacity < capacity ) { return 0; } size_t count = 0; ON_UnitName unit_name; ON_UnitNameEx x; const ON_UnitName* input_list; size_t input_list_count; for ( size_t list_index = 0; list_index < 2; list_index++ ) { switch(list_index) { case 0: input_list = si_length_units; input_list_count = si_length_units_count; break; case 1: input_list = en_US_customary_length_units; input_list_count = en_US_customary_length_units_count; break; default: input_list = 0; input_list_count = 0; break; } for ( size_t i = 0; i < input_list_count; i++ ) { if ( 0 != length_unit_list ) { length_unit_list[count++] = input_list[i]; } else if ( 0 != length_unit_ex_list ) { unit_name = input_list[i]; x.m_locale_id = unit_name.m_locale_id; x.m_unit_system = unit_name.m_unit_system; x.m_name = unit_name.m_name; if ( x.SetSimplifiedName() > 0 && 0 != x.m_utf32_name_count > 0 && 0 != x.m_utf32_name_count < ON_UnitNameEx::m_utf32_name_capacity && 0 != x.m_utf32_name[0] && 0 != x.m_utf32_name[x.m_utf32_name_count-1] && 0 == x.m_utf32_name[x.m_utf32_name_count] && 0 == x.m_utf32_name[ON_UnitNameEx::m_utf32_name_capacity-1] ) { length_unit_ex_list[count++] = x; } else { ON_ERROR("Length unit list conatins invalid element."); } } } } return (unsigned int)count; } unsigned int ON_LengthUnitName::GetLengthUnitNameList( size_t length_unit_list_capacity, ON_LengthUnitName* length_unit_list ) { return GetLengthUnitList(length_unit_list_capacity,(ON_UnitName*)length_unit_list,0,false); } int ON_ParseLengthUnitName( const wchar_t* str, int str_count, int prefered_locale_id, ON::LengthUnitSystem* length_unit_system ) { ON_ParseSettings parse_settings; parse_settings.SetPreferedLocaleId(prefered_locale_id); return ON_ParseLengthUnitName(str, str_count, parse_settings, length_unit_system); } int ON_ParseLengthUnitName( const wchar_t* str, int str_count, ON_ParseSettings parse_settings, ON::LengthUnitSystem* length_unit_system ) { unsigned int prefered_locale_id = MapPreferedLocaleId(parse_settings.PreferedLocaleId()); static ON_UnitSystemNameCache s_length_unit_cache = {0}; if ( 0 != length_unit_system ) { *length_unit_system = ON::LengthUnitSystem::None; } ON_UnitNameEx x; const unsigned int utf32_name_capacity = ON_UnitNameEx::m_utf32_name_capacity; unsigned int count = 0; int str_index = 0; x.m_locale_id = 0; x.m_unit_system = static_cast(ON::LengthUnitSystem::None); x.m_name = str; x.m_utf32_name_count = 0; x.m_utf32_name[0] = 0; int whitespace_count = 0; for (;;) { if ( 0 == str_count || str_count < -1 ) break; if ( nullptr == str ) break; if (parse_settings.ParseLeadingWhiteSpace()) { // skip over leading white space while ((-1 == str_count || whitespace_count < str_count) && parse_settings.IsLeadingWhiteSpace(str[str_index+whitespace_count])) { whitespace_count++; } } else if (parse_settings.ParseWhiteSpaceBetweenValueAndUnitSystem()) { // skip over interior white space (needed to make ON_LengthValue() parsing work correctly while ((-1 == str_count || whitespace_count < str_count) && parse_settings.IsInteriorWhiteSpace(str[str_index+whitespace_count])) { whitespace_count++; } } str += whitespace_count; if (-1 != str_count) str_count -= whitespace_count; if ( str[0] >= 0 && str[0] < 'A' && ON_UNICODE_QUOTATION_MARK != str[0] && ON_UNICODE_APOSTROPHE != str[0] ) { break; } if ( 0 == s_length_unit_cache.m_unit_list ) { if ( !GetUnitSystemNameCache(GetLengthUnitList,true,s_length_unit_cache) ) break; } if (ON_UNICODE_QUOTATION_MARK == str[0] ) { // double quote = US inches abbreviation str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::LengthUnitSystem::Inches); x.m_utf32_name[0] = ON_UNICODE_QUOTATION_MARK; x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } if (ON_UNICODE_APOSTROPHE == str[0] ) { // apostrophe = US feet abbreviation str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::LengthUnitSystem::Feet); x.m_utf32_name[0] = ON_UNICODE_APOSTROPHE; x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } str_index = ON_GetSmallSimpleUnitsName(str,x.m_utf32_name,utf32_name_capacity); if ( str_index <= 0 ) { str_index = 0; break; } while (count < utf32_name_capacity && 0 != x.m_utf32_name[count] ) count++; if ( count >= utf32_name_capacity ) { str_index = 0; count = 0; break; } x.m_utf32_name_count = count; while (count < utf32_name_capacity) x.m_utf32_name[count++] = 0; x.m_unit_system = UnitSystemEnumValue( s_length_unit_cache, prefered_locale_id, &x); if ( static_cast(ON::LengthUnitSystem::None) == x.m_unit_system ) { str_index = 0; count = 0; } break; } if ( str_index > 0 && 0 != length_unit_system ) *length_unit_system = ON::LengthUnitSystemFromUnsigned(x.m_unit_system); return (str_index > 0) ? (str_index+whitespace_count) : 0; } /////////////////////////////////////////////////////////////////////////////// // // Angle unit names // static unsigned int GetAngleUnitList( size_t angle_unit_list_capacity, ON_UnitName* angle_unit_list, ON_UnitNameEx* angle_unit_ex_list, bool bIncludeInvalidLocaleIdNames ) { const size_t angle_radian_units_count = sizeof(angle_radian_units)/sizeof(angle_radian_units[0]); const size_t angle_degree_units_count = sizeof(angle_degree_units)/sizeof(angle_degree_units[0]); const size_t angle_minute_units_count = sizeof(angle_minute_units)/sizeof(angle_minute_units[0]); const size_t angle_second_units_count = sizeof(angle_second_units)/sizeof(angle_second_units[0]); const size_t angle_turn_units_count = sizeof(angle_turn_units)/sizeof(angle_turn_units[0]); const size_t angle_gradian_units_count = sizeof(angle_gradian_units)/sizeof(angle_gradian_units[0]); const size_t angle_no_units_count = sizeof(angle_no_units)/sizeof(angle_no_units[0]); const size_t capacity = angle_radian_units_count + angle_degree_units_count + angle_minute_units_count + angle_second_units_count + angle_turn_units_count + angle_gradian_units_count + (bIncludeInvalidLocaleIdNames ? angle_no_units_count : 0) ; if ( 0 == angle_unit_list_capacity && 0 == angle_unit_list && 0 == angle_unit_ex_list ) return (unsigned int)capacity; if ( angle_unit_list_capacity < capacity || (0 == angle_unit_list && 0 == angle_unit_ex_list) ) { return 0; } if ( 0 != angle_unit_list && 0 != angle_unit_ex_list ) return 0; size_t count = 0; ON_UnitName unit_name; ON_UnitNameEx x; const ON_UnitName* input_list; size_t input_list_count; for ( size_t list_index = 0; list_index < 7; list_index++ ) { switch(list_index) { case 0: input_list = angle_radian_units; input_list_count = angle_radian_units_count; break; case 1: input_list = angle_turn_units; input_list_count = angle_turn_units_count; break; case 2: input_list = angle_degree_units; input_list_count = angle_degree_units_count; break; case 3: input_list = angle_minute_units; input_list_count = angle_minute_units_count; break; case 4: input_list = angle_second_units; input_list_count = angle_second_units_count; break; case 5: input_list = angle_gradian_units; input_list_count = angle_gradian_units_count; break; case 6: if ( bIncludeInvalidLocaleIdNames ) { input_list = angle_no_units; input_list_count = angle_no_units_count; } else { input_list = 0; input_list_count = 0; } break; default: input_list = 0; input_list_count = 0; break; } for ( size_t i = 0; i < input_list_count; i++ ) { if ( 0 != angle_unit_list ) { angle_unit_list[count++] = input_list[i]; } else { unit_name = input_list[i]; x.m_locale_id = unit_name.m_locale_id; x.m_unit_system = unit_name.m_unit_system; x.m_name = unit_name.m_name; if ( x.SetSimplifiedName() > 0 && 0 != x.m_utf32_name_count > 0 && 0 != x.m_utf32_name_count < ON_UnitNameEx::m_utf32_name_capacity && 0 != x.m_utf32_name[0] && 0 != x.m_utf32_name[x.m_utf32_name_count-1] && 0 == x.m_utf32_name[x.m_utf32_name_count] && 0 == x.m_utf32_name[ON_UnitNameEx::m_utf32_name_capacity-1] ) { angle_unit_ex_list[count++] = x; } else { ON_ERROR("Angle unit list conatins invalid element."); } } } } return (unsigned int)count; } int ON_ParseAngleUnitName( const wchar_t* str, int str_count, int prefered_locale_id, ON::AngleUnitSystem* angle_unit_system ) { ON_ParseSettings parse_settings; parse_settings.SetPreferedLocaleId(prefered_locale_id); parse_settings.SetParseLeadingWhiteSpace(false); return ON_ParseAngleUnitName(str, str_count, parse_settings, angle_unit_system); } int ON_ParseAngleUnitName( const wchar_t* str, int str_count, ON_ParseSettings parse_settings, ON::AngleUnitSystem* angle_unit_system ) { static ON_UnitSystemNameCache s_angle_unit_cache = {0}; if ( 0 != angle_unit_system ) *angle_unit_system = ON::AngleUnitSystem::None; unsigned int prefered_locale_id = MapPreferedLocaleId(parse_settings.PreferedLocaleId()); ON_UnitNameEx x; const unsigned int utf32_name_capacity = ON_UnitNameEx::m_utf32_name_capacity; unsigned int count = 0; int str_index = 0; x.m_locale_id = 0; x.m_unit_system = static_cast(ON::AngleUnitSystem::None); x.m_name = str; x.m_utf32_name_count = 0; x.m_utf32_name[0] = 0; int whitespace_count = 0; for (;;) { if ( 0 == str_count && str_count < -1 ) break; if ( 0 == str ) break; if (parse_settings.ParseLeadingWhiteSpace()) { // skip over leading white space while ((-1 == str_count || whitespace_count < str_count) && parse_settings.IsLeadingWhiteSpace(str[str_index+whitespace_count])) { whitespace_count++; } } else if (parse_settings.ParseWhiteSpaceBetweenValueAndUnitSystem()) { // skip over interior white space (needed to make ON_AngleValue() parsing work correctly while ((-1 == str_count || whitespace_count < str_count) && parse_settings.IsInteriorWhiteSpace(str[str_index+whitespace_count])) { whitespace_count++; } } str += whitespace_count; if (-1 != str_count) str_count -= whitespace_count; if ( str[0] >= 0 && str[0] < 'A' && ON_UNICODE_QUOTATION_MARK != str[0] && ON_UNICODE_APOSTROPHE != str[0] ) { break; } if ( 0 == s_angle_unit_cache.m_unit_list ) { if ( !GetUnitSystemNameCache(GetAngleUnitList,true,s_angle_unit_cache) ) break; } if (ON_UNICODE_QUOTATION_MARK == str[0] ) { // double quote = arc seconds str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::AngleUnitSystem::Seconds); x.m_utf32_name[0] = ON_UNICODE_QUOTATION_MARK; x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } if ( ON_UNICODE_APOSTROPHE == str[0] ) { // apostrophe = arc minutes str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::AngleUnitSystem::Minutes); x.m_utf32_name[0] = ON_UNICODE_APOSTROPHE; x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } if ( ON_UNICODE_DEGREE_SYMBOL == str[0] ) { // unicode degree symbol = arc degrees str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::AngleUnitSystem::Degrees); x.m_utf32_name[0] = ON_UNICODE_DEGREE_SYMBOL; x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } if ( ON_UNICODE_MASCULINE_ORDINAL_INDICATOR == str[0] ) { // The unicode masuline ordinal indicator (Spanish) // is often mistakenlyused as a degrees symbol. str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::AngleUnitSystem::Degrees); x.m_utf32_name[0] = ON_UNICODE_DEGREE_SYMBOL; // correct - convert to degree symbol x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } if ( ON_UNICODE_GREEK_SMALL_LETTER_TAU == str[0] ) { // unicode greek tau = turns str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::AngleUnitSystem::Turns); x.m_utf32_name[0] = ON_UNICODE_GREEK_SMALL_LETTER_TAU; x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } if ( ON_UNICODE_GREEK_CAPITAL_LETTER_TAU == str[0] ) { // unicode capital greek tau = turns str_index = 1; x.m_name = str; x.m_unit_system = static_cast(ON::AngleUnitSystem::Turns); x.m_utf32_name[0] = ON_UNICODE_GREEK_SMALL_LETTER_TAU; // correct - convert to lower case x.m_utf32_name[1] = 0; x.m_utf32_name_count = 1; break; } str_index = ON_GetSmallSimpleUnitsName(str,x.m_utf32_name,utf32_name_capacity); if ( str_index <= 0 ) { str_index = 0; break; } while (count < utf32_name_capacity && 0 != x.m_utf32_name[count] ) count++; if ( count >= utf32_name_capacity ) { str_index = 0; count = 0; break; } x.m_utf32_name_count = count; while (count < utf32_name_capacity) x.m_utf32_name[count++] = 0; x.m_unit_system = UnitSystemEnumValue( s_angle_unit_cache, prefered_locale_id, &x ); if ( static_cast(ON::AngleUnitSystem::None) == x.m_unit_system ) { str_index = 0; count = 0; } break; } if ( str_index > 0 && angle_unit_system ) *angle_unit_system = ON::AngleUnitSystemFromUnsigned(x.m_unit_system); return (str_index > 0) ? (str_index+whitespace_count) : 0; } unsigned int ON_AngleUnitName::GetAngleUnitNameList( size_t angle_unit_list_capacity, ON_AngleUnitName* angle_unit_list ) { return GetAngleUnitList(angle_unit_list_capacity,(ON_UnitName*)angle_unit_list,0,false); } static const wchar_t* ON_Internal_GetUnitsName( unsigned int locale_id, const unsigned int unit_system_as_unsigned, bool bPlural, size_t count, const ON_UnitName* names ) { if (count <= 0 || nullptr == names) return nullptr; const unsigned int special_id_limit = 2; if (locale_id <= special_id_limit && locale_id != ON_RHINO_LOCALE_ID) { if (0 == locale_id) locale_id = ON_Locale::CurrentCulture.WindowsLCID(); if ( locale_id <= special_id_limit && locale_id != ON_RHINO_LOCALE_ID ) locale_id = ON_RHINO_LOCALE_ID; } else if (locale_id > special_id_limit && ON_EN_US_LOCALE_ID != locale_id) { unsigned int prefered_locale_id = MapPreferedLocaleId(locale_id); if (locale_id != prefered_locale_id && prefered_locale_id > special_id_limit) locale_id = prefered_locale_id; } const wchar_t* singular_name = nullptr; const wchar_t* plural_name = nullptr; for (size_t i = 0; i < count; i++) { if (locale_id == names[i].m_locale_id && unit_system_as_unsigned == names[i].m_unit_system ) { const wchar_t* name = names[i].m_name; if (nullptr != name && 0 != name[0]) { if (nullptr == singular_name && names[i].m_bIsSingular) { if (!bPlural) return name; singular_name = name; } if (nullptr == singular_name && names[i].m_bIsPlural) { if (bPlural) return name; plural_name = name; } } } } if (nullptr != plural_name) return plural_name; if (nullptr != singular_name) return singular_name; if (ON_RHINO_LOCALE_ID == locale_id) return nullptr; // nothing left to try if (locale_id > special_id_limit && ON_EN_US_LOCALE_ID != locale_id) { // try English - US return ON_Internal_GetUnitsName(ON_EN_US_LOCALE_ID, unit_system_as_unsigned, bPlural, count, names); } // Try "rhino" locale return ON_Internal_GetUnitsName(ON_RHINO_LOCALE_ID, unit_system_as_unsigned, bPlural, count, names); } ON_LengthUnitName ON_LengthUnitName::Create( unsigned int locale_id, ON::LengthUnitSystem length_unit_system, bool bPlural ) { if (0 == locale_id) locale_id = ON_Locale::CurrentCulture.WindowsLCID(); size_t count = 0; const ON_UnitName* names = nullptr; length_unit_system = ON::LengthUnitSystemFromUnsigned(static_cast(length_unit_system)); switch (length_unit_system) { case ON::LengthUnitSystem::None: break; case ON::LengthUnitSystem::Angstroms: case ON::LengthUnitSystem::Nanometers: case ON::LengthUnitSystem::Microns: case ON::LengthUnitSystem::Millimeters: case ON::LengthUnitSystem::Centimeters: case ON::LengthUnitSystem::Decimeters: case ON::LengthUnitSystem::Meters: case ON::LengthUnitSystem::Dekameters: case ON::LengthUnitSystem::Hectometers: case ON::LengthUnitSystem::Kilometers: case ON::LengthUnitSystem::Megameters: case ON::LengthUnitSystem::Gigameters: names = si_length_units; count = sizeof(si_length_units)/sizeof(si_length_units[0]); break; case ON::LengthUnitSystem::Microinches: case ON::LengthUnitSystem::Mils: case ON::LengthUnitSystem::Inches: case ON::LengthUnitSystem::Feet: case ON::LengthUnitSystem::Yards: case ON::LengthUnitSystem::Miles: names = en_US_customary_length_units; count = sizeof(en_US_customary_length_units)/sizeof(en_US_customary_length_units[0]); break; case ON::LengthUnitSystem::PrinterPoints: break; case ON::LengthUnitSystem::PrinterPicas: break; case ON::LengthUnitSystem::NauticalMiles: break; case ON::LengthUnitSystem::AstronomicalUnits: break; case ON::LengthUnitSystem::LightYears: break; case ON::LengthUnitSystem::Parsecs: break; case ON::LengthUnitSystem::CustomUnits: break; case ON::LengthUnitSystem::Unset: break; default: ON_ERROR("Invalid length_unit_system parameter."); length_unit_system = ON::LengthUnitSystem::Unset; break; } ON_LengthUnitName length_unit_name; length_unit_name.m_locale_id = locale_id; length_unit_name.m_length_unit_system = length_unit_system; length_unit_name.m_bNameIsSingular = bPlural ? false : true; length_unit_name.m_bNameIsPlural = bPlural ? true : false; // attempt to get localized name length_unit_name.m_name = ON_Internal_GetUnitsName( locale_id, static_cast(length_unit_system), bPlural, count, names ); if (nullptr == length_unit_name.m_name || 0 == length_unit_name.m_name[0]) { switch (length_unit_system) { case ON::LengthUnitSystem::None: break; case ON::LengthUnitSystem::Angstroms: length_unit_name.m_name = bPlural ? L"angstroms" : L"angstrom"; break; case ON::LengthUnitSystem::Nanometers: length_unit_name.m_name = bPlural ? L"nanometers" : L"nanometer"; break; case ON::LengthUnitSystem::Microns: length_unit_name.m_name = bPlural ? L"microns" : L"micron"; break; case ON::LengthUnitSystem::Millimeters: length_unit_name.m_name = bPlural ? L"millimeters" : L"millimeter"; break; case ON::LengthUnitSystem::Centimeters: length_unit_name.m_name = bPlural ? L"centimeters" : L"centimeter"; break; case ON::LengthUnitSystem::Decimeters: length_unit_name.m_name = bPlural ? L"decimeters" : L"decimeter"; break; case ON::LengthUnitSystem::Meters: length_unit_name.m_name = bPlural ? L"meters" : L"meter"; break; case ON::LengthUnitSystem::Dekameters: length_unit_name.m_name = bPlural ? L"dekameters" : L"dekameter"; break; case ON::LengthUnitSystem::Hectometers: length_unit_name.m_name = bPlural ? L"hectometers" : L"hectometer"; break; case ON::LengthUnitSystem::Kilometers: length_unit_name.m_name = bPlural ? L"kilometers" : L"kilometer"; break; case ON::LengthUnitSystem::Megameters: length_unit_name.m_name = bPlural ? L"megameters" : L"megameter"; break; case ON::LengthUnitSystem::Gigameters: length_unit_name.m_name = bPlural ? L"gigameters" : L"gigameter"; break; case ON::LengthUnitSystem::Microinches: length_unit_name.m_name = bPlural ? L"microinches" : L"microinche"; break; case ON::LengthUnitSystem::Mils: length_unit_name.m_name = bPlural ? L"mils" : L"mil"; break; case ON::LengthUnitSystem::Inches: length_unit_name.m_name = bPlural ? L"inches" : L"inch"; break; case ON::LengthUnitSystem::Feet: length_unit_name.m_name = bPlural ? L"feet" : L"foot"; break; case ON::LengthUnitSystem::Yards: length_unit_name.m_name = bPlural ? L"yards" : L"yard"; break; case ON::LengthUnitSystem::Miles: length_unit_name.m_name = bPlural ? L"miles" : L"mile"; break; case ON::LengthUnitSystem::PrinterPoints: length_unit_name.m_name = bPlural ? L"points" : L"point"; break; case ON::LengthUnitSystem::PrinterPicas: length_unit_name.m_name = bPlural ? L"picas" : L"pica"; break; case ON::LengthUnitSystem::NauticalMiles: length_unit_name.m_name = bPlural ? L"nauticalmiles" : L"nauticalmile"; // no spaces! break; case ON::LengthUnitSystem::AstronomicalUnits: length_unit_name.m_name = bPlural ? L"AUs" : L"AU"; // no spaces! break; case ON::LengthUnitSystem::LightYears: length_unit_name.m_name = bPlural ? L"lightyears" : L"lightyear"; // no spaces! break; case ON::LengthUnitSystem::Parsecs: length_unit_name.m_name = bPlural ? L"parsecs" : L"parsec"; break; case ON::LengthUnitSystem::CustomUnits: break; case ON::LengthUnitSystem::Unset: break; } } return length_unit_name; } int ON_LengthUnitName::Internal_Compare( unsigned int order_selector, const ON_LengthUnitName& a, const ON_LengthUnitName& b ) { if (1 == order_selector) { // locale id is first if (a.m_locale_id < b.m_locale_id) return -1; if (a.m_locale_id > b.m_locale_id) return 1; } unsigned int i = static_cast(a.m_length_unit_system); unsigned int j = static_cast(b.m_length_unit_system); if (i < j) return -1; if (i > j) return 1; if (1 != order_selector) { // locale id is second if (a.m_locale_id < b.m_locale_id) return -1; if (a.m_locale_id > b.m_locale_id) return 1; } i = ON_wString::CompareOrdinal(a.m_name,b.m_name,false); if (i != 0) { // ignore case order is prefered j = ON_wString::CompareOrdinal(a.m_name, b.m_name, true); return (0 != j) ? j : i; } i = a.m_bNameIsSingular ? 1 : 0; j = b.m_bNameIsSingular ? 1 : 0; if (i < j) return -1; if (i > j) return 1; i = a.m_bNameIsPlural ? 1 : 0; j = b.m_bNameIsPlural ? 1 : 0; if (i < j) return -1; if (i > j) return 1; return 0; } int ON_LengthUnitName::CompareUnitSystemLocaleIdName( const ON_LengthUnitName& a, const ON_LengthUnitName& b ) { return Internal_Compare(0, a, b); } int ON_LengthUnitName::CompareLocaleIdUnitSystemName( const ON_LengthUnitName& a, const ON_LengthUnitName& b ) { return Internal_Compare(1, a, b); } unsigned int ON_LengthUnitName::LocaleId() const { return m_locale_id; } ON::LengthUnitSystem ON_LengthUnitName::LengthUnit() const { return m_length_unit_system; } bool ON_LengthUnitName::LengthUnitAndNameAreSet() const { return LengthUnitIsSet() && LengthUnitNameIsNotEmpty(); } bool ON_LengthUnitName::LengthUnitIsSet() const { return (ON::LengthUnitSystem::Unset != m_length_unit_system && ON::LengthUnitSystem::None != m_length_unit_system); } bool ON_LengthUnitName::LengthUnitIsSetOrNone() const { return (ON::LengthUnitSystem::Unset != m_length_unit_system); } const wchar_t* ON_LengthUnitName::LengthUnitName() const { return (nullptr == m_name) ? static_cast(ON_wString::EmptyString) : m_name; } bool ON_LengthUnitName::LengthUnitNameIsSingular() const { return m_bNameIsSingular; } bool ON_LengthUnitName::LengthUnitNameIsPlural() const { return m_bNameIsPlural; } bool ON_LengthUnitName::LengthUnitNameIsEmpty() const { return (nullptr == m_name || 0 == m_name[0]); } bool ON_LengthUnitName::LengthUnitNameIsNotEmpty() const { return (nullptr != m_name && 0 != m_name[0]); } bool operator==( const ON_LengthUnitName& a, const ON_LengthUnitName& b ) { return (0 == ON_LengthUnitName::CompareUnitSystemLocaleIdName(a, b)); } bool operator!=( const ON_LengthUnitName& a, const ON_LengthUnitName& b ) { return (0 != ON_LengthUnitName::CompareUnitSystemLocaleIdName(a, b)); } ON_AngleUnitName ON_AngleUnitName::Create( unsigned int locale_id, ON::AngleUnitSystem angle_unit_system, bool bPlural ) { angle_unit_system = ON::AngleUnitSystemFromUnsigned(static_cast(angle_unit_system)); size_t count = 0; const ON_UnitName* names = nullptr; switch (angle_unit_system) { case ON::AngleUnitSystem::None: break; case ON::AngleUnitSystem::Turns: names = angle_turn_units; count = sizeof(angle_turn_units)/sizeof(angle_turn_units[0]); break; case ON::AngleUnitSystem::Radians: names = angle_radian_units; count = sizeof(angle_radian_units)/sizeof(angle_radian_units[0]); break; case ON::AngleUnitSystem::Degrees: names = angle_degree_units; count = sizeof(angle_degree_units)/sizeof(angle_degree_units[0]); break; case ON::AngleUnitSystem::Minutes: names = angle_minute_units; count = sizeof(angle_minute_units)/sizeof(angle_minute_units[0]); break; case ON::AngleUnitSystem::Seconds: names = angle_second_units; count = sizeof(angle_second_units)/sizeof(angle_second_units[0]); break; case ON::AngleUnitSystem::Gradians: names = angle_gradian_units; count = sizeof(angle_gradian_units)/sizeof(angle_gradian_units[0]); break; case ON::AngleUnitSystem::Unset: break; default: ON_ERROR("Invalid angle_unit_system parameter."); angle_unit_system = ON::AngleUnitSystem::Unset; break; } ON_AngleUnitName angle_unit_name; angle_unit_name.m_locale_id = locale_id; angle_unit_name.m_angle_unit_system = angle_unit_system; angle_unit_name.m_bNameIsSingular = bPlural ? false : true; angle_unit_name.m_bNameIsPlural = bPlural ? true : false; // attempt to get localized name angle_unit_name.m_name = ON_Internal_GetUnitsName( locale_id, static_cast(angle_unit_system), bPlural, count, names ); if (nullptr == angle_unit_name.m_name || 0 == angle_unit_name.m_name[0]) { switch (angle_unit_system) { case ON::AngleUnitSystem::None: break; case ON::AngleUnitSystem::Turns: angle_unit_name.m_name = bPlural ? L"turns" : L"turn"; break; case ON::AngleUnitSystem::Radians: angle_unit_name.m_name = bPlural ? L"radians" : L"radian"; break; case ON::AngleUnitSystem::Degrees: angle_unit_name.m_name = bPlural ? L"degrees" : L"degree"; break; case ON::AngleUnitSystem::Minutes: angle_unit_name.m_name = bPlural ? L"minutes" : L"minute"; break; case ON::AngleUnitSystem::Seconds: angle_unit_name.m_name = bPlural ? L"seconds" : L"second"; break; case ON::AngleUnitSystem::Gradians: angle_unit_name.m_name = bPlural ? L"gradians" : L"gradian"; break; case ON::AngleUnitSystem::Unset: break; } } return angle_unit_name; } int ON_AngleUnitName::Internal_Compare( unsigned int order_selector, const ON_AngleUnitName& a, const ON_AngleUnitName& b ) { if (1 == order_selector) { // locale id is first if (a.m_locale_id < b.m_locale_id) return -1; if (a.m_locale_id > b.m_locale_id) return 1; } unsigned int i = static_cast(a.m_angle_unit_system); unsigned int j = static_cast(b.m_angle_unit_system); if (i < j) return -1; if (i > j) return 1; if (1 != order_selector) { // localed id is second if (a.m_locale_id < b.m_locale_id) return -1; if (a.m_locale_id > b.m_locale_id) return 1; } i = ON_wString::CompareOrdinal(a.m_name,b.m_name,false); if (i != 0) { // ignore case order is prefered j = ON_wString::CompareOrdinal(a.m_name, b.m_name, true); return (0 != j) ? j : i; } i = a.m_bNameIsSingular ? 1 : 0; j = b.m_bNameIsSingular ? 1 : 0; if (i < j) return -1; if (i > j) return 1; i = a.m_bNameIsPlural ? 1 : 0; j = b.m_bNameIsPlural ? 1 : 0; if (i < j) return -1; if (i > j) return 1; return 0; } int ON_AngleUnitName::CompareUnitSystemLocaleIdName( const ON_AngleUnitName& a, const ON_AngleUnitName& b ) { return Internal_Compare(0, a, b); } int ON_AngleUnitName::CompareLocaleIdUnitSystemName( const ON_AngleUnitName& a, const ON_AngleUnitName& b ) { return Internal_Compare(1, a, b); } unsigned int ON_AngleUnitName::LocaleId() const { return m_locale_id; } ON::AngleUnitSystem ON_AngleUnitName::AngleUnit() const { return m_angle_unit_system; } bool ON_AngleUnitName::AngleUnitAndNameAreSet() const { return AngleUnitIsSet() && AngleUnitNameIsNotEmpty(); } bool ON_AngleUnitName::AngleUnitIsSet() const { return (ON::AngleUnitSystem::Unset != m_angle_unit_system && ON::AngleUnitSystem::None != m_angle_unit_system); } bool ON_AngleUnitName::AngleUnitIsSetOrNone() const { return (ON::AngleUnitSystem::Unset != m_angle_unit_system); } const wchar_t* ON_AngleUnitName::AngleUnitName() const { return (nullptr == m_name) ? static_cast(ON_wString::EmptyString) : m_name; } bool ON_AngleUnitName::AngleUnitNameIsSingular() const { return m_bNameIsSingular; } bool ON_AngleUnitName::AngleUnitNameIsPlural() const { return m_bNameIsPlural; } bool ON_AngleUnitName::AngleUnitNameIsEmpty() const { return (nullptr == m_name || 0 == m_name[0]); } bool ON_AngleUnitName::AngleUnitNameIsNotEmpty() const { return (nullptr != m_name && 0 != m_name[0]); } bool operator==( const ON_AngleUnitName& a, const ON_AngleUnitName& b ) { return (0 == ON_AngleUnitName::CompareUnitSystemLocaleIdName(a, b)); } bool operator!=( const ON_AngleUnitName& a, const ON_AngleUnitName& b ) { return (0 != ON_AngleUnitName::CompareUnitSystemLocaleIdName(a, b)); }