03.07.2020 • C3D Converter, C3D Toolkit, C3D Modeler

Как узнать состав импортированной модели инструментами C3D Toolkit

Модуль обмена данными C3D Converter, работая с деревом модели, оперирует двумя основными сущностями — компонентом, который в свою очередь может быть деталью или сборкой, и вставкой одного компонента в другой. Возможны разные интерпретации, что считать компонентом: в C3D ему соответствует файл САПР, содержащий в разной комбинации собственные элементы (тела, кривые) и ссылки на другие компоненты. Кроме того, у компонента есть идентификатор, имя, сведения об авторе и организации.

Один из наиболее популярных вопросов — что делать с моделями, импортированными из файлов обменных форматов? Как извлечь компоненты, из которых состоит модель, с учетом вложенности?

C3D Converter умеет отображать дерево модели на объекты ядра C3D Modeler — наследники класса MbItem. Этот функционал, в частности, используется функциями семейства ImportFrom, которые работают с объектами C3D. Одну из них можно вызвать, например, таким образом:

#include <conv_i_converter.h>
c3d::ItemSPtr rootItem;
c3d::string_t importPath;//=...
const MbeConvResType importResult = c3d::ImportFromFile( rootItem, importPath, C3D_NULL_PTR, C3D_NULL_PTR );

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

В том случае, если компонент нельзя отождествить с элементом, который он содержит, формируется объект типа MbAssembly. В него включаются как собственные компоненты, так и ссылки на другие элементы. Ссылки при этом также, по возможности, сводятся к вставке компонента без использования MbInstance.

Структуру модели можно вывести на консоль следующей функцией:

//------------------------------------------------------------------------------
// Вывести структуру документа в стандартный поток
// ---
void PrintItemsInfoFromContent( const MbItem* item, const std::string& preStr ) { 
  if ( item != C3D_NULL_PTR )
    return;
  std::cout << preStr;
  PrintProductAttributes( *item );
  switch (item->IsA()) {
  case st_Solid:
    std::cout << "Тело " << ( static_cast<const MbSolid&>(*item).IsClosed() ? "замкнутое " : "открытое " ) << std::setbase(16) << item << std::setbase(10) << std::endl;
    break;
  case st_Mesh:
    std::cout << "Полигональный объект" << std::setbase(16) << item << std::setbase(10) << std::endl;
  break;
  case st_WireFrame:
    std::cout << "Проволочный каркас" << std::setbase(16) << item << std::setbase(10) << std::endl;
    break;
  case st_Instance: {
    const MbInstance& inst = static_cast<const MbInstance&>(*item);
    std::cout << "Вставка " << std::setbase(16) << inst.GetItem() << std::setbase(10) << std::endl;
    PrintItemsInfoFromContent( inst.GetItem(), preStr + "  " );
  }
  break;
  case st_Assembly: {
    std::cout << "Составной элемент " << std::setbase(16) << item << std::setbase(10) << std::endl;
    const MbAssembly& assm = static_cast<const MbAssembly&>(*item);
    for (size_t ind = 0, sz = assm.ItemsCount(); ind < sz; ind++) {
      PrintItemsInfoFromContent(assm.GetItem(ind), preStr + "  " );
    }
  } break;
  default:
    std::cout << "Нереализованный случай " << std::setbase(16) << item << std::setbase(10) << std::endl;
    break;
  }
}

По-хорошему, для каждого компонента должен быть определен, по крайней мере, его алфавитно-числовой идентификатор, чтобы пользователи могли однозначно различать их между собой. Для хранения информации, специфической для компонентов, в ядре C3D Modeler есть специальные объекты — атрибуты изделия.

Ниже приведен пример работы с двумя атрибутами изделия — обязательным MbProductInfo и опциональным MbPersonOrganizationInfo.

#include <attr_product.h>
//------------------------------------------------------------------------------
// Вывести атрибуты изделия в стандартный поток
// ---
void PrintProductAttributes( const MbItem& item ) {
  AttrVector productAttr; 
  item.GetAttributes( productAttr, at_ProductAttribute, at_ProductInfo ); 
  if ( (!productAttr.empty()) && (productAttr.front() != C3D_NULL_PTR) ) { 
    const MbProductInfo& prod = *(static_cast<MbProductInfo*>(productAttr.front())); 
    string_t id, name, descr; 
    std::cout << "* MbProductInfo * " << (prod.IsAssembly() ? "Сборка" : "Деталь") << ToSTDstring( prod.GetId() ) << " : " << ToSTDstring( prod.GetName() ) << '\t'; 
  }
  productAttr.clear(); 
  item.GetAttributes( productAttr, at_ProductAttribute, at_PersonOrganizationInfo ); 
  if ( (!productAttr.empty()) && (productAttr.front() != C3D_NULL_PTR) ) { 
    const MbPersonOrganizationInfo& persOrg = *(static_cast<MbPersonOrganizationInfo*>(productAttr.front())); 
    std::cout << "* MbPersonOrganizationInfo * " << ToSTDstring( persOrg.NameOneLine() ) << '\t'; 
  }
}

Отметим, что возможны ситуации, когда объект, являющийся потомком MbItem, не несет атрибутов изделия, но таких случаев лучше избегать. Подобные модели, как правило, построены при недостатке исходных данных в условиях, когда нужно сохранить форму изделия и его структуру.

Александр Спиваков, Руководитель разработки C3D Converter
Автор:
Александр Спиваков
Руководитель разработки C3D Converter

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

Поделиться материалом