STEP SDK: Create a DOMAIN_MODEL Assembly File

Anton Chervinsky

August 04, 2023

In some cases, it is useful to have detailed geometry descriptions in separate files and construct a final product by combining them with transformations. A significant part of the DOMAIN_MODEL for the AP242 application protocol supports assembly files. An assembly file can have links to STEP files containing parts or to other assembly files.

Create and Fill a New Assembly File
 

To create a new assembly file, use the OdStpXModelFiller class from the StepCoreTools module with an empty OdDAI::Model for the DOMAIN_MODEL schema.


  OdAnsiString workDirSchema("./Schemas/"); // Your path to .exp file
  OdDAI::SchemaPtr tutorialSchema = oddaiGetSchema(workDirSchema + "DomainModel.exp");
  if (!tutorialSchema.isNull())
  {
    OdDAI::RepositoryPtr repo = session->createRepo("StpX_Repo");
    session->openRepo(repo);

    OdDAI::ModelPtr tutorialModel = repo->createModel("Tutorial_07_Model", tutorialSchema);
    if (!tutorialModel.isNull())
    {
      tutorialModel->promoteModelToReadWrite();
      OdStpXModelFillerPtr pStpXFiller = OdStpXModelFiller::createObject(tutorialModel);

      if (pStpXFiller.isNull())
      {
        return eCreateFailed;
      }
      …
    }
  }  

To fill a model, you can use a sequence of low-level ODA SDAI calls, however, using OdStpXModelFiller (which is a high-level wrapper over the SDAI) allows you to significantly reduce the amount of code needed to create a full model. Each command adds new instances to the model and returns a smart pointer to OdDAI::ApplicationInstance of the created class instance.

For example, to create base model global instances:


OdDAI::ApplicationInstancePtr pClass = pStpXFiller->createClass("exchange identification information");
OdDAI::ApplicationInstancePtr pOrganization = pStpXFiller->createOrganization("www.opendesign.com", "Open Design Alliance", OdAnsiStringArray().insertAt(0, "company"));
OdDAI::ApplicationInstancePtr pUnit = pStpXFiller->createUnit("metre", "SI system", "milli");
OdDAI::ApplicationInstancePtr pExchangeContext = pStpXFiller->createExchangeContext("AP242 BO Model XML Assembly Structure exchange", OdAnsiStringArray().insertAt(0, "en"), pUnit->id(), pOrganization->id());
OdDAI::ApplicationInstancePtr pViewContext = pStpXFiller->createViewContext("mechanical design", "design");
OdDAI::ApplicationInstancePtr pFormatProperty = pStpXFiller->createFormatProperty("ISO 8859-1", "ISO 10303-242 BO Model XML");

Add a Part to the Model
 

The DOMAIN_MODEL schema manages industrial products such as parts, and its data exchange includes at least one element of the Part type.

The next code example illustrates adding a new Part instance to the model:


OdDAI::ApplicationInstancePtr pIdentifierRoot = pStpXFiller->createIdentifier("Tutorial_07", pClass->id(), pOrganization->id());
OdDAI::ApplicationInstancePtr pAssemblyDefinitionRoot = pStpXFiller->createAssemblyDefinition(pViewContext->id());

OdDAIObjectIds rootViewsIds;
rootViewsIds.push_back(pAssemblyDefinitionRoot->id());
OdDAI::ApplicationInstancePtr pPartVersionRoot = pStpXFiller->createPartVersion("/NULL", rootViewsIds);

OdDAIObjectIds rootPartVersionsIds;
rootPartVersionsIds.push_back(pPartVersionRoot->id());
OdDAI::ApplicationInstancePtr pPartRoot = pStpXFiller->createPart(pIdentifierRoot->id(), "Tutorial_07", "assembly", rootPartVersionsIds);

Using a SingleOccurrence is necessary to position each occurrence in 3D space. If a single-level or multi-level assembly structure uses the same component part multiple times, a distinct instance of a SingleOccurrence is created for each use of the component. In some PDM systems, each instance of a SingleOccurrence referenced by NextAssemblyOccurrenceUsage in an assembly part has a unique ID. All of them are defined under the PartView or AssemblyDefinition of the component part and they are referenced only once via NextAssemblyOccurrenceUsage.

To make a transformation operation between two created PartView of Parts:


OdDAI::ApplicationInstancePtr pIdentifierRoot = pStpXFiller->createIdentifier("Tutorial_07", pClass->id(), pOrganization->id());
OdDAI::ApplicationInstancePtr pAssemblyDefinitionRoot = pStpXFiller->createAssemblyDefinition(pViewContext->id());

OdDAIObjectIds rootViewsIds;
rootViewsIds.push_back(pAssemblyDefinitionRoot->id());
OdDAI::ApplicationInstancePtr pPartVersionRoot = pStpXFiller->createPartVersion("/NULL", rootViewsIds);

OdDAIObjectIds rootPartVersionsIds;
rootPartVersionsIds.push_back(pPartVersionRoot->id());
OdDAI::ApplicationInstancePtr pPartRoot = pStpXFiller->createPart(pIdentifierRoot->id(), "Tutorial_07", "assembly", rootPartVersionsIds);

Associate a Document with a Part

Documents can be associated with a part instance in a specific role using a document assignment, which represents the relationship between a document and other elements of product data. Constraints can be specified on this association to specify only the applicable portion of a document or file. A role value of a document assignment is required for files that contain the geometry of the part.

The next code example illustrates creating a document assignment and associating it with DigitalFile instances for a part:


OdDAI::ApplicationInstancePtr pDigitalFileIdentifier = pStpXFiller->createIdentifier(pAssemblyFile->fileName, pClass->id(), pOrganization->id());
OdDAI::ApplicationInstancePtr pDigitalFile = pStpXFiller->createDigitalFile(pDigitalFileIdentifier->id(), pFormatProperty->id(), "File name");
OdDAI::ApplicationInstancePtr pDocumentAssignment = pStpXFiller->createDocumentAssignment("mandatory", pDigitalFile->id(), pPartView->id());

Fill Structures

You can use auxiliary structures to easily fill the required structures. For example, the following set of structures can help you specify the relationship between objects and files. The AssemblyPart structure stores an array of nested Parts instances with a transformation matrix. Each nested part can have another array of nested Parts instances or be associated with a file containing geometry.

struct AssemblyBase
{
  virtual ~AssemblyBase() {}
};
struct AssemblyFile : AssemblyBase
{
  AssemblyFile(const OdAnsiString& name) : fileName(name) {}
  OdAnsiString fileName;
};
struct AssemblyPart : AssemblyBase
{
  OdArray<std::pair<AssemblyBase*, OdGeMatrix3d> > assemblies;
};

An assembly file should have the composition of Parts instances with references between them. A root part refers to nested parts, which can refer to other nested parts or have relationships with geometry files.

Example

See Tutorial 7 in the ExStepTutorials example module for examples of creating a DOMAIN_MODEL assembly file. The file generated by the tutorial can be opened in Open Step Viewer.

Find out more in our documentation.