Справочник по настройке CAM-системы
  • Справочник по настройке CAM-системы
Search Results for

    Show / Hide Table of Contents
    • Справочник по настройке CAM-системы
    • Фреймворк XMLProperties
      • Обзор фреймворка
      • Синтаксис дескрипторов
      • Язык выражений
      • Использование XML-свойств из кода
      • Пользовательские значения по умолчанию
    • XML-дескрипторы операций
      • Дескрипторы операций
      • Справочник иерархии операций
    • Дескрипторы станков
      • Дескрипторы станков
      • Справочник узлов станка
      • Справочник параметров Machine Setup
      • Продвинутые темы по станкам
      • 3D-модели станков

    Использование XML‑свойств из кода

    Свойства, которые вы объявляете в XML, — это те же свойства, что вы читаете и записываете из кода. Они доступны из нескольких окружений — CAM API (.NET, C++, …), нативных пакетов Delphi / C++, .NET‑постпроцессоров и постпроцессоров .sppx — и, что важно, шаблон доступа во всех них одинаков. Эта глава один раз описывает общий шаблон, а затем показывает небольшие особенности каждого окружения.

    1 Одна модель, один шаблон доступа, много окружений

    Вспомните различие типы и экземпляры. Из любого окружения вы работаете с экземплярами: живым деревом свойств конкретного объекта, где каждый узел — это указатель свойства. Через указатель вы читаете или записываете его значение, заходите в потомков, ищете и изучаете его дескриптор для метаданных типа.

    Указатель всегда предоставляет одни и те же именованные аксессоры, в каком бы окружении вы ни были:

    Аксессор Что делает
    Str[name] / Int[name] / Flt[name] / Bol[name] читают и записывают значение потомка как строку / целое / double / логическое
    Ptr[name] получить указатель на потомка (чтобы зайти в ComplexType)
    Arr[name] получить дочерний массив
    ValueAsString / ValueAsInteger / ValueAsDouble / ValueAsBoolean собственное значение указателя
    FindChild / FindProperty найти потомка по имени

    Имена могут быть составными, и регистр не важен. Вместо пошагового спуска через Ptr передавайте точечный путь прямо в аксессор, а к элементам массива по ключу или индексу обращайтесь через (…):

    Flt["RoughPasses.StepValue"]          # вложенное значение, через точку
    Int["controldata.usearc"]             # регистронезависимо
    Flt["Axes(AxisXPos).Value"]           # элемент массива по ключу, затем потомок
    Str["Project.Operations(0).Name"]     # элемент массива по индексу
    

    Одни и те же имена аксессоров, тот же точечный/регистронезависимый поиск и тот же синтаксис массивов (key) присутствуют в каждом окружении; различается только языковая обёртка:

    Окружение Тип указателя COM‑обёртка?
    CAM API (.NET / C++ / …) IST_XMLPropPointer да
    Нативные пакеты Delphi / C++ IST_XMLPropPointer нет
    .NET‑постпроцессоры INamedProperty нет
    Постпроцессоры .sppx (Pascal‑подобный язык) встроенный нет

    Поэтому §2–9 ниже — это вариант .NET CAM API: встречающиеся там ComWrapper, Invoke / InvokeAndWrap и using — это обёртка .NET‑COM, а не часть модели свойств. Нативное окружение и постпроцессоры (§10–12) используют те же имена аксессоров без этой церемонии.

    Как узнать полное имя свойства

    Чтобы пользоваться аксессорами, нужно полное точечное имя свойства. Быстрее всего получить его из работающей программы:

    1. Откройте инспектор свойств операции и найдите свойство.
    2. У правого края его строки нажмите кнопку ⋯ (три точки), чтобы открыть меню строки, и выберите «Скопировать имя свойства в буфер обмена».

    В том же меню есть «Настроить…», открывающее окно, где показано не только вычисленное значение свойства, но и его исходное выражение — удобно, когда значение параметризовано от других свойств (см. язык выражений). (Это окно есть только в недавних версиях.)

    Старые версии — обходной путь. Если окна «Настроить…» нет, воспользуйтесь контекстным меню операции → «Сохранить как пользовательскую операцию». В открывшемся окне найдите свойство в инспекторе, щёлкните по нему правой кнопкой и используйте там «Скопировать имя свойства в буфер обмена». Затем уберите ведущий RefOperations(0). из скопированного имени — он появляется лишь потому, что это окно показывает копию свойств внутри отдельной сущности UserOperation, а не живую операцию. Останется имя, которое вы передаёте аксессорам.

    2 Как получить дерево свойств объекта

    Объекты предметной области предоставляют своё дерево свойств через член XMLProp. Для технологической операции:

    using var xmlPropsCom = operationCom.InvokeAndWrap(operation => operation.XMLProp);
    

    XMLProp — это единое дерево свойств объекта. Для свойств, хранящихся только в XMLProp (современный случай), оно авторитетно — для чтения/записи не нужен отдельный шаг фиксации. Но некоторые операции до сих пор дублируют отдельные значения в собственных полях объекта (унаследованный код); там XMLProp и объект могут разойтись и должны синхронизироваться через SaveToXMLProp / LoadFromXMLProp — см. §7.

    Тот же шаблон с XMLProp применим к станкам, инструментам и другим объектам.

    3 Чтение и запись значений по имени

    Каждый узел предоставляет типизированные индексаторы по имени потомка: Str, Flt, Int, Bol. Это идиома, используемая во всех примерах — значение задаётся присваиванием индексатору:

    // из FullWorkflow3DProject/TechnologyHelper.cs
    using var xmlPropsCom = operationCom.InvokeAndWrap(operation => operation.XMLProp);
    xmlPropsCom.Invoke(xmlProps =>
    {
        xmlProps.Str["DrillingType"] = "HolePocketing";   // записать строку / id варианта перечисления
    });
    

    Чтение симметрично:

    xmlPropsCom.Invoke(xmlProps =>
    {
        double step  = xmlProps.Flt["StepValue"];
        int    count = xmlProps.Int["StepCount"];
        bool   on    = xmlProps.Bol["Enabled"];
        string mode  = xmlProps.Str["DrillingType"];
    });
    

    Как и в любом окружении (§1), имя может быть точечным путём и регистронезависимо, так что можно добраться до вложенного значения за один вызов, а не спускаться через Ptr (§4):

    double step = xmlProps.Flt["RoughPasses.StepValue"];
    bool   on   = xmlProps.Bol["roughpasses.enabled"];   // регистр игнорируется
    

    Сначала проверьте существование

    Свойство может отсутствовать на конкретном объекте (например, необязательный или пользовательский параметр). Защищайте чтение через PropExists:

    var value = xmlProps.PropExists["DrillingType"]
        ? xmlProps.Str["DrillingType"]
        : "";
    

    Перечисления — по ID или по индексу. Значение перечисления — это ID варианта, поэтому Str["DrillingType"] = "ChipRemoving" задаёт его по ID (ID варианта, а не его подпись — см. §3.2). Можно также читать или записывать его по нулевому индексу варианта через Int: Int["DrillingType"] = 2 выбирает третий вариант, а чтение Int["DrillingType"] возвращает индекс текущего варианта. (Это работает в каждом окружении.)

    Удобный слой‑обёртка (.NET)

    Пакет‑хелпер для .NET оборачивает эти индексаторы в методы‑расширения над ComWrapper<IST_XMLPropPointer>, что позволяет обойтись без явного Invoke:

    double step = xmlPropsCom.Flt("StepValue");      // геттер
    xmlPropsCom.SetFlt("StepValue", 2.5);            // сеттер
    xmlPropsCom.SetStr("DrillingType", "ChipRemoving");
    string calc = xmlPropsCom.CStr("SomeComputed");  // вычисленное значение вычисляемого свойства
    

    Хелперы есть для каждого типа (Str/Flt/Int/Bol и их формы Set…), плюс Ptr, Arr, FindProperty, FindPropertyInWholeScope и другие. Используйте любой стиль, подходящий вашему коду; все они вызывают один и тот же низлежащий интерфейс.

    4 Навигация по дереву

    Заход в составные типы

    Ptr[name] (или хелпер Ptr(name)) спускается в потомка‑ComplexType; дальше продолжайте типизированными индексаторами. Это отражает точечные пути из вашего XML (RoughPasses.StepValue):

    xmlPropsCom.Invoke(xmlProps =>
    {
        var rough = xmlProps.Ptr["RoughPasses"];
        rough.Bol["Enabled"]   = true;
        rough.Flt["StepValue"] = 1.0;
    });
    

    Поиск по имени

    Когда не хочется выписывать полный путь, ищите по поддереву:

    using var dt = xmlPropsCom.FindPropertyInWholeScope("DrillingType");
    string current = dt.ValueAsString();
    dt.SetNodeValue("ChipRemoving");
    

    FindPropertyInWholeScope возвращает первое совпадение на любой глубине — предпочитайте цепочки Ptr (или ограниченный областью FindProperty), когда имя может быть неуникальным.

    5 Массивы

    Дочерний массив — это IST_XMLPropArray, получаемый через Arr[name]. Он поддерживает создание и добавление элементов поверх обычных операций с указателем. Вот реальный шаблон добавления пользовательского элемента массива:

    // из ExtensionOperationParamsNet/OperationCustomPropsHelper.cs
    const string arrayId = "CustomOperationPropertiesArray";
    using var paramArrayCom = ComWrapper.Create(operation.XMLProp.Arr[arrayId]);
    
    if (!operation.XMLProp.PropExists[fullId])
    {
        var newItem = paramArrayCom.Invoke(a => a.CreateNewItem("CustomOperationProperty"));
        newItem.Str["Name"] = paramId;
        paramArrayCom.Invoke(a => a.AddItem(newItem));
    }
    

    Адресация элемента массива по ключу

    Когда у элемента массива есть член Name/ключ, можно обратиться к нему напрямую синтаксисом пути ArrayName(key) в индексаторе — без ручного перебора:

    var fullId = $"{arrayId}({paramId})";          // например, CustomOperationPropertiesArray(MyParam)
    operation.XMLProp.Str[fullId] = "true";        // чтение/запись значения элемента
    bool exists = operation.XMLProp.PropExists[fullId];
    

    6 Собственное значение указателя

    Аксессоры из §3 читают потомка по имени (Str["StepValue"]). Когда у вас уже есть указатель на само свойство (а не на его родителя), читайте или записывайте его собственное значение. Это тоже типизировано — ValueAsString, ValueAsDouble, ValueAsInteger, ValueAsBoolean (см. список аксессоров в §1). ValueAsString применим к любому типу свойства и возвращает его строковое представление:

    double v   = somePropCom.ValueAsDouble();   // типизированное собственное значение
    string raw = somePropCom.ValueAsString();   // любой тип → его текстовая форма
    somePropCom.SetNodeValue("75");             // задать собственное значение указателя
    

    7 Операции: синхронизация полей объекта с XMLProp

    (Только для операций.) Для операции XMLProp — это её единое дерево свойств с двумя задачами: единое дерево времени выполнения (чтобы общий код мог показать любую операцию в инспекторе и значения можно было копировать между операциями) и форма, в которой свойства операции сериализуются в/из XML при сохранении или загрузке проекта.

    Исторически операции хранили свои значения в обычных полях объекта, а XMLProp был добавлен позже сверху. Поэтому унаследованные свойства живут в обоих местах — в полях объекта и в XMLProp — и обе копии нужно держать согласованными:

    • SaveToXMLProp — заталкивает текущие значения полей операции в XMLProp. Вызывайте перед чтением XMLProp (например, перед заполнением инспектора из дерева), чтобы дерево отражало актуальное состояние объекта.
    • LoadFromXMLProp — читает значения из XMLProp обратно в поля объекта. Вызывайте после правки XMLProp (например, после того как пользователь изменил значение в инспекторе), чтобы модель объекта подхватила изменение.

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

    LoadFromXMLProp также принимает XMLProp другой операции — именно так настройки одной операции копируются из другой:

    operationCom.LoadFromXmlProp(otherXmlPropsCom);   // применить чужое дерево свойств к этой операции
    

    SaveToXmlProp() возвращает свойства операции в виде дерева (с уже сброшенными в него полями объекта) — удобно для снимка, сравнения или переноса.

    8 Изучение дескрипторов и значений по умолчанию

    Каждый указатель свойства связан со своим дескриптором (IST_XMLPropDescriptor), который несёт объявленные вами в XML метаданные — имя, подпись, простой тип, значение по умолчанию, пользовательские атрибуты, наследование. Используйте его, когда нужно рассуждать о схеме, а не о значении (например, обобщённо перечислить параметры объекта или прочитать пользовательский атрибут, заданный на дескрипторе).

    Значения по умолчанию доступны через IST_PropDefaultsEditor (запрашивается у дескриптора): он различает системное значение по умолчанию (объявленное в XML дескриптора) и любое пользовательское переопределение, для метрической и дюймовой систем единиц, и позволяет читать, задавать или сбрасывать пользовательское значение по умолчанию.

    9 Практические заметки

    • Освобождайте COM‑обёртки. Указатели свойств и массивы — это COM‑объекты; оборачивайте их в using, чтобы они освобождались своевременно. В примерах работа выполняется внутри лямбд Invoke / InvokeAndWrap, которые управляют временем жизни за вас.
    • Используйте точный ID из дескриптора — имена должны совпадать с объявленными в XML.
    • Задавайте перечисления и логические значения их каноническим текстом — ID варианта для перечислений; для логических значений в примерах используются строки "true"/"false" через Str[...] либо типизированный индексатор Bol[...].
    • Не боритесь с вычисляемыми значениями. Свойство, значение которого определяется выражением DefaultValue/Visible, будет пересчитываться; читайте его вычисленный результат через CStr (или ValueAsCalculatedString), а если нужно хранить фиксированное значение, сделайте его реальным редактируемым полем.
    • Куда смотреть дальше. Репозиторий cam-api-examples (Operation/ExtensionOperationParamsNet, FullWorkflow, ProjectMachine) содержит полные компилируемые примеры использования всего вышеописанного.

    10 Нативное использование (Delphi / C++)

    Нативные пакеты предоставляют тот же указатель свойства через публичный IST_XMLPropPointer. Нет COM‑обёртки, нет Invoke, нет using: вы держите обычную ссылку на интерфейс и вызываете те же аксессоры напрямую. Методы объекта предметной области LoadFromXMLProp / SaveToXMLProp (и LoadConditionsFromXMLProp) получают такой указатель:

    procedure LoadFromXMLProp(XMLProp: IST_XMLPropPointer);
    var p: IST_XMLPropPointer;
    begin
      if XMLProp <> nil then with XMLProp do begin
        p := FindProp('SafeLevel');
        if p <> nil then with p do begin
          fZRetract.IsAbs  := Int['ReferenceType'] = 0;   // те же аксессоры Int[…]/Flt[…]
          fZRetract.IncVal := Flt['RelValue'];
          fZRetract.AbsVal := Flt['AbsValue'];
        end;
      end;
    end;
    

    Это те же Int[…] / Flt[…] / Str[…] / Bol[…] / FindProp, что и из .NET — просто без COM‑церемонии.

    11 В .NET‑постпроцессорах (INamedProperty)

    Постпроцессор на .NET читает именованные свойства команды/проекта, которые ему передали, и выдаёт УП. Он использует чисто‑.NET‑слой без COM — INamedProperty, но доступ тот же: индексаторы Str / Int / Flt / Bol / Ptr / Arr плюс ValueAsString / ValueAsInteger / ValueAsDouble / ValueAsBoolean, с привычными точечными, регистронезависимыми именами и адресацией массивов (key) / (index):

    double x      = cmd.Flt["Axes(AxisXPos).Value"];
    int    origin = cmd.Int["OriginType"];
    double ox     = cmd.Flt["WCS.OriginPoint.X"];
    

    Разобранный постпроцессор есть в репозитории postprocessors-examples в Features/NamedParameters/DemoOfWritePPFun (см. WritePPFun.cs). Тот пример — слегка необычный контекст: он записывает параметры в файл — но доступ к свойствам ровно такой, как выше.

    12 В постпроцессорах .sppx (Pascal‑подобный язык)

    Постпроцессоры .sppx пишутся на специальном Pascal‑подобном языке. Набор доступных типов отличается, но имена методов и способ доступа к свойствам идентичны. В фрагментах ниже Cmd — один из таких объектов со свойствами — текущая команда CLData — и те же аксессоры применимы к любому объекту свойств: .Int["…"] / .Flt["…"] / .Str["…"] / .Bol["…"] для значений и .Ptr["…"] для указателя на дочернее свойство, все с привычными точечными / (key) именами:

    if Cmd.Ptr["Axes(AxisXPos)"] <> 0 then          // указатель на дочернее свойство (здесь: существует ли ось?)
      X = Cmd.Flt["Axes(AxisXPos).Value"]
    if Cmd.Int["Axes(AxisAPos).BrakeState"] > 0 then ...
    CurG68_2_X = Round(Cmd.Flt["WCS.OriginPoint.X"], 4)
    

    (реальный пример: MyDocuments\Postprocessors\Mill\Fanuc (30i)_Mill.sppx)


    Далее: Пользовательские значения по умолчанию · Назад к оглавлению.

    In this article
    Back to top Generated by DocFX