Получение дерева всех элементов сборки с учётом исполнений

Автор Cyclopentan, 08.11.21, 17:12:09

« предыдущая - следующая »

0 Пользователей и 1 гость просматривают эту тему.

Cyclopentan

Коллеги, добрый день!
Передо мной стоит задача построить всю структуру сборки (что достаточно просто), но при этом учитывать все исполнения всех вложенных сборок и деталей (что оказалось не очень-то просто).

Для примера возьмём вот такую тривиальную ситуацию:
Сборка А,    в неё входит Сборка Б,    в неё входит Сборка В.
Сборка А-01, в неё входит Сборка Б,    в неё входит Сборка В.
Сборка А-02, в неё входит Сборка Б-01, в неё входит Сборка В-01.

Для первого уровня, вроде, всё прекрасно работает через IEmbodimentsManager:
IPart7 P1Level = doc7.TopPart;
IEmbodimentsManager EM1Level = (IEmbodimentsManager)P1Level;
for (int i = 0; i < EM1Level.EmbodimentCount; i++)
{
  Embodiment E1Level = EM1Level.get_Embodiment(i);
  IPart7 P1Level = E1Level.Part;
  Logger(P1Level.Marking);
}
Как результат цикл пробегает по всем исполнениям, берёт от них интерфейс IPart7 и выводит в консоль:
A
A-01
A-02
Вроде бы всё прекрасно. Но. Если попробовать глянуть в исполнения для сборок второго уровня со следующим кодом:
IPart7 P1Level = doc7.TopPart;
IEmbodimentsManager EM1Level = (IEmbodimentsManager)P1Level;
for (int i = 0; i < EM1Level.EmbodimentCount; i++)
{
  Embodiment E1Level = EM1Level.get_Embodiment(i);
  IPart7 P1Level = E1Level.Part;
  Logger(P1Level.Marking);
  Object[] arr = P1Level.PartsEx[1];
  for (int j = 0; j < arr.GetLength(0); j++)
  {
    P2Level= (IPart7)arr[j];
    IEmbodimentsManager EM2Level = (IEmbodimentsManager)P2Level;
    for (int k = 0; k < eemPart7.EmbodimentCount; k++)
    {
      Embodiment E2Level = EM2Level.get_Embodiment(k);
      Logger(EM2Level.GetEmbodimentMarking(k, Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Получаем шифр исполнения из IEmbodimentsManager
      Logger(E2Level.GetMarking(Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Получаем шифр исполнения из Embodiment
    }
  }
}
то получим ошибку.
При этом EM2Level.GetEmbodimentMarking отлично показывает исполнения Б и Б-01.
А E2Level.GetMarking валится с ошибкой "Ссылка на объект не указывает на экземпляр объекта".

Вопрос - это я криворукий, или в Компасе действительно есть какое-то ограничение на доступ к исполнениям не верхнего уровня?

KrissKross

тут какое-то странное поведение заложено в системе ИМХО
Embodiment E2Level = EM2Level.get_Embodiment(k); - вроде как получает Исполнение
но по факту Объект нулевой

для того чтобы с ним работать - надо делать его текущим,
с помощью метода SetCurrentEmbodiment - Установить текущее исполнение по имени или индексу

а потом получить текущее исполнение
IEmbodiment embodiment = embodimentsManager.CurrentEmbodiment;

и только после этого уже можно с ним работать
embodiment.GetMarking

Cyclopentan

Ух... Надеялся, что такого не придётся делать, иначе загрузка всего проекта будет похожа на спецэффекты из фильма "Эффект бабочки".
Но, почему-то, даже такой трюк не получился. Добавил в код из предыдущего поста назначение текущего исполнения:
Embodiment E2Level = EM2Level.get_Embodiment(k);
bool result = EM2Level.SetCurrentEmbodiment(k);
Embodiment E2Level = EM2Level.CurrentEmbodiment;


Получилось так:
IPart7 P1Level = doc7.TopPart;
IEmbodimentsManager EM1Level = (IEmbodimentsManager)P1Level;
for (int i = 0; i < EM1Level.EmbodimentCount; i++)
{
  Embodiment E1Level = EM1Level.get_Embodiment(i);
  IPart7 P1Level = E1Level.Part;
  Logger(P1Level.Marking);
  Object[] arr = P1Level.PartsEx[1];
  for (int j = 0; j < arr.GetLength(0); j++)
  {
    P2Level= (IPart7)arr[j];
    IEmbodimentsManager EM2Level = (IEmbodimentsManager)P2Level;
    for (int k = 0; k < EM2Level.EmbodimentCount; k++)
    {
      bool result = EM2Level.SetCurrentEmbodiment(k);
      Embodiment E2Level = EM2Level.CurrentEmbodiment;
      Logger(result);
      Logger(EM2Level.GetEmbodimentMarking(k, Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Получаем шифр исполнения из IEmbodimentsManager
      Logger(E2Level.GetMarking(Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Получаем шифр исполнения из Embodiment
    }
  }
}

Результат прежний - GetEmbodimentMarking отрабатывает корректно, GetMarking падает с ошибкой "Ссылка на объект не указывает на экземпляр объекта".
При этом result возвращает true, т.е. Компас уверен, что мы сменили исполнение. Однако исполнение вложенного Part-а визуально не меняется.
Для исполнений первого уровня, как и говорил, всё работает на ура.

KrissKross

Встречный вопрос
а что Вы собственно в конечном итоге хотите получить?

Этот код же работает
Logger(EM2Level.GetEmbodimentMarking(k, Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Получаем шифр исполнения из IEmbodimentsManager

Зачем еще - дублирование
Logger(E2Level.GetMarking(Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Получаем шифр исполнения из Embodiment

Которое почему-то не работает

Cyclopentan

Мне в итоге нужны параметры и структура всех исполнений, не только первого уровня.
Вот тривиальный пример:
Сборка А, в неё входит Сборка Б, в неё входит Деталь В .
У Сборки Б есть исполнение Сборка Б-01, в неё входит Деталь Г.
Из EM2Level.GetEmbodimentMarking я могу получить только то, что у входящую в сборку А подсборки Б есть исполнение Б-01. Просто строчку с обозначением.
Из E2Level я могу получить полноценный IPart7 для Б-01, и в итоге получить все его параметры, материал, МЦХ и прочее.
Более того, в Б-01 входит деталь Г, которая вообще не фигурирует в А. И до этой детали можно будет добраться только из Б-01.

KrissKross

:sun:
Так бы сразу

Для чтения внутренностей подсборки

1. либо открывать в отдельном окне
IKompasDocument3D doc3d3 = app.Documents.Open(item2.FileName) as IKompasDocument3D;
2. либо редактировать на месте
IPart7 item2;
OpenDocumentParam openDocumentParam = item2.GetOpenDocumentParam();
IKompasDocument3D doc3d = item2.BeginEdit(openDocumentParam);
// IKompasDocument3D doc3d = app.ActiveDocument as IKompasDocument3D;
item2.EndEdit(false);

Cyclopentan

Моя уверенность в собственной рукожопости растёт при каждом изменении кода.
Открываем вложенную Сборку Б на редактирование:
IPart7 P2Level= (IPart7)arr[j];
IKompasDocument3D L2doc = L2Part.BeginEdit(L2Part.GetOpenDocumentParam());
Берём менеджер исполнений от полученного Doc3D:
IEmbodimentsManager L2EM = (IEmbodimentsManager)L2doc;Берём исполнение от него же:
Embodiment L2E = L2EM.Embodiment[k];Выводим данные в лог от L2EM и L2E:
Logger(L2EM.GetEmbodimentMarking(k, Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true));
Logger(L2E.GetMarking(Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true));
В первом случае имеем Б.
Во втором случае имеем А.  :cl:
Если взять L2EM не от L2doc, а от открытого L2Part, то первый логгер так же выведет Б, а второй свалится с ошибкой.

KrissKross

Попробуйте - Исполнения взять не у Документа-3Д, а от ТопПарта

IEmbodimentsManager L2EM = (IEmbodimentsManager)L2doc;

IKompasDocument3D L2doc = L2Part.BeginEdit(L2Part.GetOpenDocumentParam());
IPart7 topchik = L2doc.TopPart;
IEmbodimentsManager L2EM = (IEmbodimentsManager)topchik;

Cyclopentan

Угу, так тоже пробовал. Всё-равно вылится с ошибкой:
IKompasDocument3D L2doc = L2Part.BeginEdit(L2Part.GetOpenDocumentParam());
IPart7 topchik = L2doc.TopPart;
IEmbodimentsManager L2EM = (IEmbodimentsManager)topchik;
Embodiment L2E = L2EM.CurrentEmbodiment;
Logger(L2EM.GetEmbodimentMarking(k, Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Возвращает Б
Logger(L2E.GetMarking(Kompas6Constants.ksVariantMarkingTypeEnum.ksVMFullMarking, true)); //Ссылка на объект не указывает на экземпляр объекта
Попробую сейчас открывать всё вложенное дерево сборок и деталей как отдельные файлы в Компасе, но то вообще какой-то сюр. Особенно если учесть, что этот пересчёт должен происходить при каждом закрытии головной сборки - пользователи просто офигеют.

KrissKross

еще попробуйте
как зашли в режим редактирования
взять текущий активный документ-3Д
IKompasDocument3D doc3d;

IPart7 item2;
OpenDocumentParam openDocumentParam = item2.GetOpenDocumentParam();
item2.BeginEdit(openDocumentParam);
IKompasDocument3D doc3d = app.ActiveDocument as IKompasDocument3D;
item2.EndEdit(false);

KrissKross

можете прислать в личку
Код и 3Д-модели
посмотрю целиком

также приступил к изучению этой темы

Cyclopentan

Думаю, не лишним будет добавить сюда комментарий от технической поддержки Аскон:

ЦитироватьФункциональность IEmbodimentsManager ограничена возможностью получения/установки нужного исполнения для вставки. Функции получения интерфейсов  Embodiment для вставок не реализованы.
Есть возможность получить список обозначений всех исполнений, используя метод IEmbodimentsManager::GetEmbodimentsTree.

Беда.
Придётся действительно отдельно открывать все файлы вложенных сборок отдельно.

KrissKross

Благодарю за разъяснения,
также и тех поддержку за оперативность


Cyclopentan

Кстати, спасибо за совет с открытием документа.
Совет годный, с открытием всё работает. Единственное, открывать лучше в фоновом режиме:
IKompasDocument3D doc3d3 = app.Documents.Open(item2.FileName, false) as IKompasDocument3D;
Тогда пользователь особо и не заметит ничего.