ADN Open CIS
Сообщество программистов Autodesk в СНГ

17/11/2013

Сокращенное наименование единиц измерения

Сегодня мы рассмотрим как можно получить единицу измерения для любого заданного параметра, а также подходящее сокращенное наименование этой единицы измерения.

В Revit 2014 появилось новое API для работы с единицами измерения, с помощью которого можно легко решить те проблемы, с которыми мы сталкивались ранее при работе с единицами измерения. И я еще до сих пор не изучил подробно все эти методы.

Вот небольшой обзор из раздела Что нового в Revit 2014 API:

API для работы с единицами измерения

API для работы с единицами измерениями было значительно расширено и изменено. Методы

  • Document.GetUnits()
  • Document.SetUnits()

предназначены для работы с единицами измерения проекта. Класс Units содержит методы доступа к таким данным единицы измерения как

  • DecimalSymbol
  • DigitGroupingAmount
  • DigitGroupingSymbol
  • FormatOptions

Класс FormatOptions предоставляет доступ свойствам форматирования единицы измерения, включая:

  • Округление (Rounding)
  • Точность (Accuracy)

Метод LabelUtils.GetLabelFor() был улучшен и теперь с помощью него мы можем получить наименование типа единицы измерения (UnitSymbolType).

Форматирование единиц измерения и парсинг

Методы:

  • UnitFormatUtils.FormatValueToString()
  • UnitFormatUtils.TryParse()

позволяют отформатировать значение в строку желаемого вида, а также наоборот, получить числовое значение из форматированной строки.

Конвертация единиц измерения

Новый класс UnitUtils содержит методы для конвертации между различными типами единиц измерений:

  • UnitUtils.Convert() – Конвертация из одного типа в другой. Например, из квадратных футов в квадратные метры.
  • UnitUtils.ConvertFromInternalUnits() – Конвертирует значение из внутреннего типа единицы измерения Revit.
  • UnitUtils.ConvertToInternalUnits() – Конвертирует значение во внутренний тип единицы измерения Revit.

Фактически, очень немногие знают об этой довольно мощной функциональности Revit API.

Я понял это, когда в очередной раз получил вопрос о том как получить сокращенное наименование единицы измерения:

Вопрос: Как можно получить единицу измерения для определенного параметра?

Я пытался воспользоваться методом LabelUtils.GetLabelFor(), передавая в качестве параметра DisplayUnitType. Метод возвращает полное наименование единицы измерения, например, «Миллиметры», для типа DUT_MILLIMETERS.

Я бы хотел получить сокращенное наименование, типа «мм».

Как можно этого добиться?

Ответ: Прежде всего, поздравляю вас с исследованием подхода, который вы описали.

Описание параметра содержит базовый тип единицы измерения для параметра, например, длина, или более сложный, например, сила. Все возможные типы единиц измерения можно найти в перечислении типа UnitType.

Сам же параметр содержит свойство, в котором определяется единица измерения, которая увидит пользователь. Это определяется настройками единиц измерения, и можно задать, например, фт., м., или мм. для длины и кг/(м*с2) или МПа для силы. Все возможные типы единиц измерения для отображения пользователю, находятся в перечислении DisplayUnitType.

Мы уже рассматривали одну из проблем конвертирования и форматирования единиц измерения (на англ.) более тщательно, где мы задали соответствие между типом единицы измерения параметра и типом единицы измерения проекта, создали свой класс ParameterUnitConverter и внешнюю команду CmdParameterUnitConverter, которую вы можете найти в примерах The Building Coder, и недавно рассматривали улучшения при работе с Parameter.DisplayUnitType.

Класс LabelUtils содержит методы, с помощью которых можно получить значение перечислений DisplayUnitType, UnitType, и других в том виде, в котором их видит пользователь в интерфейсе.

Вы уже попробовали этот способ.

Если же вам нужно получить аббревиатуры единиц измерения, вместо их полного наименования, то возможно наиболее эффективным будет создание своего собственного списка с сокращенными наименованиями.

Но есть еще один способ. Вы можете воспользоваться новыми методами Revit API и получить этот список с помощью новой функциональности.

Я обсужу оба способа, реализую внешнюю команду и дам ссылку на скачивание.

Как реализовать собственный список сокращенных наименований единиц измерения

Вы можете создать свой собственный список сокращенных наименований довольно легко.

Я сделал свой список, но лишь для первых 26 значений перечисления:

Код - C#: [Выделить]
  1.   /// <summary>
  2.   /// Жестко закодированные сокращенные названия единиц измерения
  3.   /// Для первых 26 значений перечисления DisplayUnitType.
  4.   /// </summary>
  5.   public static string[] DisplayUnitTypeAbbreviation
  6.     = new string[] {
  7.       "м", // DUT_METERS = 0,
  8.       "см", // DUT_CENTIMETERS = 1,
  9.       "мм", // DUT_MILLIMETERS = 2,
  10.       "фут", // DUT_DECIMAL_FEET = 3,
  11.       "N/A", // DUT_FEET_FRACTIONAL_INCHES = 4,
  12.       "N/A", // DUT_FRACTIONAL_INCHES = 5,
  13.       "дюйм", // DUT_DECIMAL_INCHES = 6,
  14.       "акр", // DUT_ACRES = 7,
  15.       "г", // DUT_HECTARES = 8,
  16.       "N/A", // DUT_METERS_CENTIMETERS = 9,
  17.       "ярд3", // DUT_CUBIC_YARDS = 10,
  18.       "фт2", // DUT_SQUARE_FEET = 11,
  19.       "м2", // DUT_SQUARE_METERS = 12,
  20.       "фт3", // DUT_CUBIC_FEET = 13,
  21.       "м3", // DUT_CUBIC_METERS = 14,
  22.       "град", // DUT_DECIMAL_DEGREES = 15,
  23.       "N/A", // DUT_DEGREES_AND_MINUTES = 16,
  24.       "N/A", // DUT_GENERAL = 17,
  25.       "N/A", // DUT_FIXED = 18,
  26.       "%", // DUT_PERCENTAGE = 19,
  27.       "дюйм2", // DUT_SQUARE_INCHES = 20,
  28.       "см2", // DUT_SQUARE_CENTIMETERS = 21,
  29.       "мм2", // DUT_SQUARE_MILLIMETERS = 22,
  30.       "дюйм3", // DUT_CUBIC_INCHES = 23,
  31.       "см3" // DUT_CUBIC_CENTIMETERS = 24,
  32.       "мм3", // DUT_CUBIC_MILLIMETERS = 25,
  33.       "л" // DUT_LITERS = 26,
  34.     };

Имейте ввиду что это жестко закодированный массив, проиндексированный по целочисленному значению перечисления DisplayUnitType.

Можно исползовать любый сокращения, какие хотите.

Массив вернет верные значения сокращенных наименований, только для тех единиц измерения, которые содержатся в этом массиве.

Но, было бы неплохо избежать хардкода и создания собственного списка аббревиатур, не таки ли? И, это можно сделать.

Как автоматически сгенерировать список сокращенных наименований единиц измерения с помощью Revit API

Как я уже сказал, Revit API содержит множество полезных функций для работы с единицами измерения, и о некоторых вы уже возможно слышали и использовали.

Сначала я рассматривал способ для получения сокращений из значения, отформатированного в желаемую единицу измерения с помощью методов FormatUtils.Format или UnitFormatUtils.Format.

Эти методы позволяют отформатировать числовое значение с единицей измерения в строку, исходя из переданных параметров, или из параметров проекта.

Если вы установите в настройках проекта, что нужно использовать миллиметры, передадите UT_Length в качестве типа единицы измерения и число 1, то я хотел бы получить строку «1 мм», из которой затем получить только сокращенное наименование.

Но этот способ я оставлю читателям, в качестве упражнения. Потому что я предпочел все же работать с единицами измерения, которые отображаются пользователю (DisplayUnitType) и полностью избежать работу с неотображаемыми пользователю единицами измерения (UnitType), которые требуются для работы вышеуказанных методов.

После более глубокого изучения документации по Revit API, я наткнулся на метод FormatOptions GetValidUnitSymbols, который судя по описанию делает как раз то что нужно: принимает в качестве параметра DisplayUnitType и возвращает список всех подходящих единиц измерения в виде перечисления UnitSymbolType, которое используется при форматировании.

Вот список первых 22 значений перечисления. Всего их около 300:

Код - C#: [Выделить]
  1.   UST_NONE = 0,
  2.   UST_M = 1,
  3.   UST_CM = 101,
  4.   UST_MM = 201,
  5.   UST_LF = 301,
  6.   UST_FOOT_SINGLE_QUOTE = 302,
  7.   UST_INCH_DOUBLE_QUOTE = 601,
  8.   UST_ACRES = 701,
  9.   UST_HECTARES = 801,
  10.   UST_CY = 1001,
  11.   UST_SF = 1101,
  12.   UST_FT_SUP_2 = 1102,
  13.   UST_FT_CARET_2 = 1103,
  14.   UST_M_SUP_2 = 1201,
  15.   UST_M_CARET_2 = 1202,
  16.   UST_CF = 1301,
  17.   UST_FT_SUP_3 = 1302,
  18.   UST_FT_CARET_3 = 1303,
  19.   UST_M_SUP_3 = 1401,
  20.   UST_M_CARET_3 = 1402,
  21.   UST_DEGREE_SYMBOL = 1501,
  22.   UST_PERCENT_SIGN = 1901,
  23.   ...

Если приглядеться к значениям перечисления, то можно заметить, что наименования очень похожи на те что мы создали самостоятельно. Все что нужно, это заменить _SUP_ на ^, убрать первые 4 символа UST_ и привести к нижнему регистру.

Я создал вот такой вспомогательный метод:

Код - C#: [Выделить]
  1.   /// <summary>
  2.   /// Конвертирует значение перечисления UnitSymbolType
  3.   /// в читаемую строку.
  4.   /// </summary>
  5.   public static string UnitSymbolTypeString(
  6.     UnitSymbolType u )
  7.   {
  8.     string s = u.ToString();
  9.  
  10.     Debug.Assert( s.StartsWith( "UST_" ),
  11.       "Ожидается перечисление UnitSymbolType "
  12.       + "начинающееся с 'UST_'" );
  13.  
  14.     s = s.Substring( 4 )
  15.       .Replace( "_SUP_", "^" )
  16.       .ToLower();
  17.  
  18.     return s;
  19.   }

Внешняя команда CmdDutAbbreviation для тестирования

Я добавил новую команду CmdDutAbbreviation для тестирования двух методов для получения сокращенного наименования единиц измерения в примеры The Building Coder.

Очевидно, что используется эта команда только для чтения, так как мы ничего не меняем в модели, поэтому я пометил ее соответствующим атрибутом.

Команды выглядит так:

Код - C#: [Выделить]
  1.   public Result Execute(
  2.     ExternalCommandData commandData,
  3.     ref string message,
  4.     ElementSet elements )
  5.   {
  6.     DisplayUnitType n
  7.       = DisplayUnitType.DUT_GALLONS_US;
  8.  
  9.     string valid_unit_symbols;
  10.  
  11.     for( DisplayUnitType i = DisplayUnitType
  12.       .DUT_METERS; i < n; ++i )
  13.     {
  14.       valid_unit_symbols = string.Join( ", ",
  15.         FormatOptions.GetValidUnitSymbols( i )
  16.           .Select<UnitSymbolType, string>(
  17.             u => Util.UnitSymbolTypeString( u ) ) );
  18.  
  19.       Debug.Print( "{0,6} - {1}: {2}",
  20.         Util.DisplayUnitTypeAbbreviation[(int)i],
  21.         LabelUtils.GetLabelFor( i ),
  22.         valid_unit_symbols,
  23.         i );
  24.     }
  25.     return Result.Succeeded;
  26.   }

Для первых 26 значений перечисления DisplayUnitType результат выглядит так:

     м - Метры: none, m

    см - Сантиметры: none, cm

    мм - Миллиметры: none, mm

   фут - Десятичные футы: none, foot_single_quote, lf

   N/A - Футы и дробные дюймы: none

   N/A - Дробные дюймы: none

  дюйм - Десятичные дюймы: none, inch_double_quote

   акр - Акры: none, acres

     г - Гектары: none, hectares

   N/A - Метры и сантиметры: none

  ярд3 - Куб. ярды: none, cy

   фт2 - Кв. футы: none, sf, ft^2

    м2 - Кв. метры: none, m^2

   фт3 - Куб. футы: none, cf, ft^3

    м3 - Куб. метры: none, m^3

  град - Десятичные градусы: none, degree_symbol

   N/A - Градусы-минуты-секунды: none

   N/A - Общие: none

   N/A - Фиксированные: none

     % - Процент: none, percent_sign

 дюйм2 - Кв. дюймы: none, in^2

   см2 - Кв. сантиметры: none, cm^2

   мм2 - Кв. миллиметры: none, mm^2

 дюйм3 - Куб. дюймы: none, in^3

   см3 - Куб. сантиметры: none, cm^3

   мм3 - Куб. миллиметры: none, mm^3

     л - Литры: none, l

               

Загрузка

Полный код  примеров как всегда доступен на GitHub . Версия, обсуждаемая сегодня – 2014.0.105.0.

Источник: http://thebuildingcoder.typepad.com/blog/2013/11/unit-abbreviations.html

 

Дополнение

Спасибо Джереми за то что подробно описал как можно получить сокращенные единицы измерения.

Однако, как можно заметить, его способ совершенно не годится для локализованных версий Revit, в т.ч. русской версии.

Класс LabelUtils тем и хорош, что он возвращает наименование, которое видит пользователь, вне зависимости от того в какой языковой версии он работает. Если пользователь работает в русской версии, то метод LabelUtils.GetLabelFor возвратит наименование на русском языке, если в английской, то на английском.

Уж не знаю почему, но Джереми пошел трудным путем, и сделал собственную реализацию метода получения сокращенного наименования единиц измерения.

Ведь один из перегруженных методов LabelUtils.GetLabelFor принимает в качестве аргумента именно UnitSymbolType. Таким образом, чтобы получить сокращенное наименование, достаточно вызвать метод LabelUtils.GetLabelFor(UnitSymbolType)

Преимущество этого метода также в том, что метод возвратит локализованное наименование.

Полный код команды для получения сокращенного наименования единицы измерения, с использованием метода LabelUtils.GetLabelFor(UnitSymbolType) выглядит вот так:

Код - C#: [Выделить]
  1.     [Transaction(TransactionMode.ReadOnly)]
  2.     public class Command : IExternalCommand
  3.     {
  4.         public Result Execute(
  5.           ExternalCommandData commandData,
  6.           ref string message,
  7.           ElementSet elements)
  8.         {
  9.             DisplayUnitType n
  10.       = DisplayUnitType.DUT_GALLONS_US;
  11.           
  12.             string valid_unit_symbols;
  13.  
  14.             for (DisplayUnitType i = DisplayUnitType
  15.               .DUT_METERS; i < n; ++i)
  16.             {
  17.                 var validUnitSymbols = FormatOptions.GetValidUnitSymbols(i);
  18.  
  19.                 foreach (var validUnitSymbol in validUnitSymbols)
  20.                 {
  21.                     if (validUnitSymbol != UnitSymbolType.UST_NONE)
  22.                     {
  23.                         var abbrUnitTypeLabel = LabelUtils.GetLabelFor(validUnitSymbol);
  24.                         Debug.Print("{0} - {1}", abbrUnitTypeLabel, LabelUtils.GetLabelFor(i));
  25.                     }                   
  26.                 }
  27.               
  28.             }
  29.             return Result.Succeeded;
  30.         }
  31.     }

И результат:

м - Метры

см - Сантиметры

мм - Миллиметры

' - Десятичные футы

Погонный фут - Десятичные футы

" - Десятичные дюймы

акр - Акры

га - Гектары

Куб. ярд - Куб. ярды

Кв. фут - Кв. футы

фт² - Кв. футы

м² - Кв. метры

Куб. фут - Куб. футы

фт³ - Куб. футы

м³ - Куб. метры

° - Десятичные градусы

% - Процент

дюйм² - Кв. дюймы

см² - Кв. сантиметры

мм² - Кв. миллиметры

дюйм³ - Куб. дюймы

см³ - Куб. сантиметры

мм³ - Куб. миллиметры

Л - Литры

 

 

Обсуждение: http://adn-cis.org/forum/index.php?topic=326

Опубликовано 17.11.2013