Overview

Products and their relationships are fundamental to IFC data. The spatial arrangement is established as a strictly hierarchical tree by IfcRelAggregates and IfcRelContainedInSpatialStructure instances. In addition, IfcRelVoidsElement instances establish removal volumes on the product structure, similar to the CSG boolean result instances within a shape representation.

Use the API documented below to navigate these relationships in IFC assemblies. After reading an IFC file, call the ifcx_asm_tag() function. This scans the IFC relations and adds extra information for efficient access. Only call the function once unless you change the assembly structure.

This creates an index for the product tree that gives a linear ordering of the products across all sub-assemblies. This index simplifies work with the spatial structure of the file as shown in the example below. An IFC product only appears once in an assembly. This differs from STEP assemblies which may reuse a product, such as a bolt, in many places.

Most of the API functions take and return an IfcObjectDefinition, which is a supertype of both IfcProject and IfcProduct. Generally, only the root of the tree will be an IfcProject and all children will be IfcProducts.

Example

The following example builds the assembly index and prints the spatial structure of an IFC file. It assumes an indent() function that indents by a certain number of spaces.

RoseDesign * d = ROSE.findDesign(AC20-FZK-Haus.ifc);
ifcx_asm_tag(d);

unsigned i,sz;
IfcxAsmProductIndex * pidx = ifcx_asm_product_index(d);

for (i=0, sz=pidx->size(); i<sz; i++)
{
    IfcObjectDefinition * pd = pidx->getAsmObjDef(i);
    IfcRelationship * rel = pidx->getAsmRel(i);
    unsigned depth = pidx->getAsmDepth(i);

    indent(depth);  // assume a function that indents by X spaces
    printf([%u] %s#%lu %s %s\n, i,
	   pidx->isProduct(i)? PRODUCT : ,
	   pd->entity_id(),
	   pd->domain()->name(),
	   pd->Name()? pd->Name(): (null name));

    indent(depth+1);
    if (rel) 
	printf(%s #%lu %s,
	       pidx->isContained(i)? CONTAIN: AGG,
	       rel->entity_id(), rel->domain()->name());
    else
	printf(ROOT OBJECT);

    printf( subtree count %u, pidx->getAsmSize(i));

    if (pidx->getAsmParentUse(i) != ROSE_NOTFOUND)
    {
	printf( parent-usage %u, pidx->getAsmParentUse(i));
    }
    printf(\n);

    if (pidx->hasVoids(i))
    {
	indent(depth+1);
	printf(HAS VOIDS\n);
    }	
    printf(\n\n);
}    

Running this on a sample file, we get something like the following:

[0] #66 IfcProject Projekt-FZK-Haus
   ROOT OBJECT subtree count 108

   [1] PRODUCT #389 IfcSite Gelaende
      AGG #400 IfcRelAggregates subtree count 107 parent-usage 0

      [2] PRODUCT #434 IfcBuilding FZK-Haus
         AGG #436 IfcRelAggregates subtree count 106 parent-usage 1

         [3] PRODUCT #479 IfcBuildingStorey Erdgeschoss
            AGG #481 IfcRelAggregates subtree count 45 parent-usage 2

            [4] PRODUCT #20909 IfcSpace 4
               AGG #20914 IfcRelAggregates subtree count 1 parent-usage 3

    ... Many entries omitted ...

            [104] PRODUCT #74280 IfcWindow OG-Fenster-1
               CONTAIN #35172 IfcRelContainedInSpatialStructure subtree count 1 parent-usage 48

            [105] PRODUCT #75347 IfcWallStandardCase Wand-Ext-OG-4
               CONTAIN #35172 IfcRelContainedInSpatialStructure subtree count 1 parent-usage 48

            [106] PRODUCT #75775 IfcAnnotation (null name)
               CONTAIN #35172 IfcRelContainedInSpatialStructure subtree count 1 parent-usage 48

            [107] PRODUCT #76112 IfcAnnotation (null name)
               CONTAIN #35172 IfcRelContainedInSpatialStructure subtree count 1 parent-usage 48

ifcx_asm_child_objs_get/size()

IfcObjectDefinition * ifcx_asm_child_objs_get(
	IfcObjectDefinition * obj,
	unsigned i
	);
	
unsigned ifcx_asm_child_objs_size(
	IfcObjectDefinition * obj
	);

The ifcx_asm_child_objs_get() function returns the combined children from both aggregates and contained relationships. The ifcx_asm_child_objs_size() function returns the number of objects present.

ifcx_asm_child_relagg_get/size()

IfcRelAggregates * ifcx_asm_child_relagg_get(
	IfcObjectDefinition * obj,
	unsigned i
	);
	
unsigned ifcx_asm_child_relagg_size(
	IfcObjectDefinition * obj
	);

The ifcx_asm_child_relagg_get() function gets the child assembly relations associated with this object. This is the "DecomposedBy" inverse relationship in the IFC model. The ifcx_asm_child_relagg_size() function returns the number of relations present.

ifcx_asm_child_relcontain_get/size()

IfcRelContainedInSpatialStructure * ifcx_asm_child_relcontain_get(
	IfcObjectDefinition * obj,
	unsigned i
	);
	
unsigned ifcx_asm_child_relcontain_size(
	IfcObjectDefinition * obj
	);

The ifcx_asm_child_relcontain_get() function gets the child contains relations associated with this object. This is the "ContainsElements" inverse relationship in the IFC model. The ifcx_asm_child_relcontain_size() function returns the number of relations present.

ifcx_asm_has_rels()

int ifcx_asm_has_rels(
	IfcObjectDefinition * obj
	);

The ifcx_asm_has_rels() function returns nonzero if object has parent, child, or void relations

ifcx_asm_is_tagged()

int ifcx_asm_is_tagged (RoseDesign * d);

The ifcx_asm_is_tagged() function returns nonzero if ifcx_asm_tag() has been called on the design to build an assembly index.

ifcx_asm_parent()

IfcObjectDefinition * ifcx_asm_parent(
	IfcObjectDefinition * obj
	);

The ifcx_asm_parent() function returns the parent object in the assembly, if one exists. The IFC spec says that objects must be in a strict spatial hierarchy, so there shouldn't be more than one aggregates or spatial containment parent relationship on anything.

ifcx_asm_parent_relagg_get/size()

IfcRelAggregates * ifcx_asm_parent_relagg_get(
	IfcObjectDefinition * obj,
	unsigned i
	);

unsigned ifcx_asm_parent_relagg_size(
	IfcObjectDefinition * obj
	);

The ifcx_asm_parent_relagg_get() function returns the enclosing assembly relations that this object appears in. This is the "Decomposes" inverse relationship in the IFC model. In well formed data, ifcx_asm_parent_relagg_size() should not return more than one.

ifcx_asm_parent_relcontain_get/size()

IfcRelContainedInSpatialStructure * ifcx_asm_parent_relcontain_get(
	IfcObjectDefinition * obj,
	unsigned i
	);
	
unsigned ifcx_asm_parent_relcontain_size(
	IfcObjectDefinition * obj
	);

The ifcx_asm_parent_relcontain_get() function returns the enclosing contains relations that this object appears in. This is the "ContainsElements " inverse relationship in the model. In well formed data ifcx_asm_parent_relcontain_size() should not return more than one.

ifcx_asm_product_index()

IfcxAsmProductIndex * ifcx_asm_product_index(
	RoseDesign * d
	);

The ifcx_asm_product_index() function returns the assembly product tree index for a given file. The index is built by calling ifcx_asm_tag() after reading the file into memory.

ifcx_asm_tag()

void ifcx_asm_tag (RoseDesign * d);

The ifcx_asm_tag() function looks at the project, product, and relationship instances in the file and builds an index for easier use. This function recognizes assemblies, annotates them with backpointers, and determines the correct parent-child direction for relationships.

You must call this function before using any of the assembly functions or managers described on this page. If the assembly structure changes, call this function again to rebuild the index.

ifcx_asm_untag()

void ifcx_asm_untag (RoseDesign * d);

The ifcx_asm_untag() function cleans up the assembly index information built by ifcx_asm_tag(). This function is provided because it is used internally when rebuilding the index. There is no need for user code to call this function since the index will be deleted when the design is deleted.

ifcx_asm_void_objs_get/size()

IfcFeatureElementSubtraction * ifcx_asm_void_objs_get(
	IfcObjectDefinition * obj,  // only used on IfcElements
	unsigned i
	);
unsigned ifcx_asm_void_objs_size(
	IfcObjectDefinition * obj   // only used on IfcElements
	);

The ifcx_asm_void_objs_get() function returns the subtraction elements that are applied to this product by voids relations. The ifcx_asm_void_objs_size() function returns the number of such voids present.

ifcx_asm_void_rels_get/size()

IfcRelVoidsElement * ifcx_asm_void_rels_get(
	IfcObjectDefinition * obj,  // only used on IfcElements
	unsigned i
	);
unsigned ifcx_asm_void_rels_size(
	IfcObjectDefinition * obj   // only used on IfcElements
	);

The ifcx_asm_void_rels_get() function gets the voids relations that are applied to this object. This is the "HasOpenings" inverse relationship in the IFC model. The ifcx_asm_void_rels_size() function returns the number of such void relations present.

ifcx_product_find_body()

IfcRepresentation * ifcx_product_find_body(
	IfcProduct * obj
	);

The ifcx_product_find_body() function searches through the representations associated with a product for one that has a RepresentationIdentifier of Body. The body representation gives the physical shape of the product.