Hide menu
Loading...
Searching...
No Matches
Product Structure

Model class

The ModelData::Model class encapsulates a data structure which eventually contains entire information about the 3D model. ModelData::Model contains a product structure, or a hierarchy of elements, often called a scene graph.

The model object is used by readers:

ModelData::Model aModel;
ModelData::ModelReader aReader;
bool anIsOk = aReader.Read (aSource, aModel);

Product structure is provided via a graph that describes hierarchical relationship between the elements.

The graph supports the following element types (which are subclasses of ModelData::ModelElement ):

  • ModelData::Part is a leaf node in a graph, corresponding to a mechanical part or a product. A part is something logically undivisible and often consists of a single body (e.g. solid body).
  • ModelData::Assembly is a group which contains zero, one or more graph elements, including nested sub-assemblies.
  • ModelData::Instance is a particular occurence of (or a reference to) another element (part or assembly). Allows to share elements and associate individual attributes (e.g. colors) and transformation matrices.

Example – as1 assembly

Below is an example of an assembly named "as1" and its graph.

Assembly
Scene graph of an assembly model

The following code demonstrates creation of a graph:

ModelData::Assembly aRoot ("as1");
aModel.AddRoot (aRoot);
...
ModelData::Assembly aNBA ("nut-bolt-assembly");
ModelData::Part aBolt ("bolt");
aNBA.AddInstance (aBolt, aBTransformation, "bolt_1");
...
ModelData::Assembly aLBA ("l-bracket-assembly");
aLBA.AddInstance (aNBA, aNBATransformation, "nut-bolt-assembly_1");
aRoot.AddInstance (aLBA, aLBATransformation, "l-bracket-assembly_1");
...

Element types

Part

ModelData::Part is a leaf node in a graph, corresponding to a mechanical part. A part is something logically undivisible (in the context of application). A part has representations (see Part representations) which define geometrical shape of the part.

The following picture demonstrates a bolt part from the assembly as1:

Part

Assembly

ModelData::Assembly is a group which contains zero, one or more graph elements, including nested sub-assemblies.

The following picture demonstrates the nut-bolt-assembly from the assembly as1. The nut-bolt-assembly includes two parts - a bolt and a nut.

Assembly

Instance

ModelData::Instance is a particular occurence of some element (part or assembly). Instances allow to share elements and to associate transformation matrices.

The following picture demonstrates the l-bracket-assembly, which includes a single l-bracket part (in green) and three instances of the nut-bolt-assembly, each with a different transformation matrix.

Assembly with 3 instances of the same sub-assembly

Sharing graph elements

Parts and (sub-)assemblies may be shared between assemblies. For instance, in the example above, the "nut-bolt-assembly" is used three times by the "l-bracket-assembly".

Sharing is enabled by using unique instances which refer to the same shared element and have unique transformation matrices and names, for instance:

ModelData::Assembly aLBA ("l-bracket-assembly");
aLBA.AddInstance (aNBA, aNBATransformation1, "nut-bolt-assembly_1");
aLBA.AddInstance (aNBA, aNBATransformation2, "nut-bolt-assembly_2");
aLBA.AddInstance (aNBA, aNBATransformation3, "nut-bolt-assembly_3");

Instances shall always be unique and shall never be shared.

Validity Requirements

Data model contents must meet certain requirements in order to ensure correct processing by Manufacturing Toolkit. Key requirements are documented below:

Product Structure Requirements

Product structure must meet the following requirements:

  • Roots may be parts and assemblies only. Instances may not be roots.
  • Assembly's children are always instances, so an instance shall be created to refer to a part or a nested sub-assembly.
  • A part may have zero or one Boundary Representation.
  • Bodies of B-Rep (inside the same part or between the parts) may not share subshapes. Each subshape must have a single parent body.

Traversal of the product structure

The product structure can be traversed using two approaches:

Traversal using iterators

Iterators support a Java-style interface.

The root elements of the graph can be traversed as follows:

ModelData::ModelElementIterator anIterator (aModel);
while (anIterator.HasNext()) {
const ModelData::ModelElement& anElement = anIterator.Next();
//...
}

To traverse the assembly children the iterator can be used as follows:

const ModelData::Assembly& anAsm = ...;
ModelData::ModelElementIterator anIterator (anAsm);
while (anIterator.HasNext()) {
const ModelData::ModelElement& anElement = anIterator.Next();
const ModelData::Instance& anInstance = static_cast<const ModelData::Instance&> (anElement);
//...
}

Traversal using visitors

The graph implements the visitor pattern, and even more specifically the hierarchical visitor pattern.

Each graph element (part, assembly, instance) accepts a visitor which must be a subclass of an abstract class ModelData::ModelElementVisitor with redefined methods to visit respective element type. The element invokes respective visitor's methods and (recursively) sends the visitor to nested elements. This mechanism ensures visiting of entire graph or a sub-tree starting with some particular element.

The following example demonstrates how to count types of all elements in the graph:

class ElementCounter : public ModelData::ModelElementVisitor
{
public:
ElementCounter() : myAsmCount (0), myInstanceCount (0), myPartCount (0) {}
size_t AsmCount() const { return myAsmCount; }
size_t InstanceCount() const { return myInstanceCount; }
size_t PartCount() const { return myPartCount; }
virtual bool VisitEnter (const ModelData::Assembly& /*theAssembly*/) override { ++myAsmCount; return true; }
virtual void VisitLeave (const ModelData::Assembly& /*theAssembly*/) override {}
virtual bool VisitEnter (const ModelData::Instance& /*theInstance*/) override { ++myInstanceCount; return true; }
virtual void VisitLeave (const ModelData::Instance& /*theInstance*/) override {}
virtual void operator() (const ModelData::Part& /*thePart */) override { ++myPartCount; }
private:
size_t myAsmCount;
size_t myInstanceCount;
size_t myPartCount;
};
ElementCounter aCounter;
aModel.Accept (aCounter);
std::cout << "The graph contains " <<
aCounter.AsmCount() << " assembly(ies), " <<
aCounter.InstanceCount() << " instance(s), " <<
aCounter.PartCount() << " part(s)" << std::endl;

If the redefined VisitEnter() method returns false then the respective assembly or instance will not be visited, i.e. assembly's children or instance's referred element will be skipped.

Traversal may start at any element in the hierarchy. For instance, to count the number of children and the element itself the above visitor can be used as follows:

ModelData::ModelElement& anElement = ... ; //either part, or assembly, or instance
ElementCounter aCounter;
anElement.Accept (aCounter);
std::cout << "The element contains " << aCounter.PartCount() << " part(s)" << std::endl;

Taking transformation matrices into account

When traversing the assembly graph which may contain multiple shared components, make sure to track transformation matrices applied to different instances along the graph in order to correctly convert local coordinates to global ones. This is typically organized using a stack that contains transformation matrices accumulated while traversing the tree.

The following example provides some excerpts of how the exploration could be organized:

class SceneGraphVisitor : public ModelData::ModelElementVisitor
{
public:
SceneGraphVisitor()
{
Geom::Transformation anIdentity;
myTrsfs.push (anIdentity);
}
protected:
virtual bool VisitEnter (const ModelData::Instance& theInstance) override
{
Geom::Transformation aTrsf;
if (theInstance.HasTransformation()) {
aTrsf = theInstance.Transformation();
}
Geom::Transformation aCumulativeTrsf = CurrentTransformation() * aTrsf;
myTrsfs.push (aCumulativeTrsf);
return true;
}
virtual void VisitLeave (const ModelData::Instance& /*theInstance*/) override
{
myTrsfs.pop();
}
const Geom::Transformation& CurrentTransformation() const
{
return myTrsfs.top();
}
private:
std::stack<Geom::Transformation> myTrsfs;
};

Helper Visitor classes

To reduce the amount of user code to be created, the data model offers a few helper classes: