ODA IFC SDK Developer's Guide > IFC Data Management > Standard Data Access Interface in IFC SDK > Work with Attributes > Work with Aggregate Attributes
Work with Aggregate Attributes

An aggregate attribute is an attribute that is represented by an application instance. This means that one application instance is included (acts as a part of an assembly) in another instance (a container). This section illustrates how to get access to aggregate attributes and sequentially walk through a collection of such attributes.

Work with a List of Application Instances

The first case of an application instance with an aggregate attribute is when each attribute is represented with a handle to another instance. For example, a polyline object is a set of points that defines the polyline route. A polyline can be stored in an .ifc file as the following:


#173= IFCCARTESIANPOINT((-2232.66666666677,-11000.));
#175= IFCCARTESIANPOINT((3767.33333333345,-11000.));
#177= IFCCARTESIANPOINT((3767.33333333345,7000.));
#179= IFCCARTESIANPOINT((-1534.66666666668,7000.));
#181= IFCCARTESIANPOINT((-1534.66666666668,4000.));
#183= IFCCARTESIANPOINT((-2232.66666666677,4000.));

#185= IFCPOLYLINE((#173,#175,#177,#179,#181,#183,#173));
    

The polyline (handle 185) is described with six points; each point is a separate application instance. The aggregate attributes can be accessed in two ways:

Whichever way you prefer, you have to use the sdaiAGGR data type to store an aggregate attribute extracted from the parent instance by calling the sdaiGetAttrBN() function. To get the parent instance, use the sdaiGetEntityById() function.


SdaiAppInstance applicationInstance = _sdaiGetEntityById(model, 185);
if ((applicationInstance == NULL) || (sdaiErrorQuery() != sdaiNO_ERR))
  return;

SdaiAggr  aggregate = NULL;

if (sdaiGetAttrBN(applicationInstance, "points", sdaiAGGR, &aggregate ) == NULL)
  return;
    

To get aggregate attribute items via an index, use the sdaiGetAggrByIndex() function. This function accepts four parameters:

  • An aggregate instance that contains the needed attributes.
  • The index value of the attribute to get.
  • The data type of the requested attribute.
  • A raw pointer to the attribute value.

The function returns a raw pointer to the attribute value stored in the fourth output parameter.

First, create an array with aggregate attribute handles to read.


const SdaiInteger checkHandleData[] = { 173, 175, 177, 179, 181, 183, 173 };
const SdaiInteger checkHandleDataLength = sizeof(checkHandleData) / sizeof(checkHandleData[0]);
    

Get the number of aggregate attributes by calling the sdaiGetMemberCount() function. The value returned by this function is used as a bound of the cycle used to iterate through attributes:


const SdaiInteger indexUpperBound = sdaiGetMemberCount(aggregate);
for (SdaiInteger instanceIndex = 0; instanceIndex < indexUpperBound; ++instanceIndex )
{
  SdaiAppInstance  instanceFromAggrIndex = NULL;

  if (sdaiGetAggrByIndex(aggregate, instanceIndex, sdaiINSTANCE, &instanceFromAggrIndex ) != NULL)
  {
    if (instanceIndex >= checkHandleDataLength)
      return;

    if (_sdaiGetEntityId(instanceFromAggrIndex) != checkHandleData[instanceIndex])
      return;
  }
  else
  {
    return;
  }
}
    

The other way to get an aggregate attribute is to use an iterator object to get sequential access to attributes. To get the iterator, use the sdaiCreateIterator() function. For interaction with the attributes collection, use the following functions:


SdaiIterator aggregateIterator = sdaiCreateIterator(aggregate);
if(sdaiErrorQuery() != sdaiNO_ERR)
  return;

SdaiInteger iterationCounter = 0;

for (sdaiBeginning(aggregateIterator); sdaiNext(aggregateIterator); ++iterationCounter)
{
  SdaiAppInstance  instanceFromIterator = NULL;
  if (sdaiGetAggrByIterator(aggregateIterator, sdaiINSTANCE, &instanceFromIterator ) != NULL)
  {
    if (iterationCounter >= checkHandleDataLength) 
      return;

    if (_sdaiGetEntityId(instanceFromIterator) != checkHandleData[iterationCounter])
      return;
  }
}
    

When you do not need the iterator anymore, call the sdaiDeleteADB() function to free the memory allocated by the iterator object:


sdaiDeleteADB(aggregateIterator);
    

Read an Attribute Data Block from a Set

This section illustrates how to exclude an aggregate attribute value using attribute data block functions.

Assume that your IFC model contains the following instance:


#94 = IFCUNITASSIGNMENT ((#43,#45,#46,#50,#52,#55,#57,#58,#60,#64,#69,#71,#72, #73,#74,#75,#76,#77,#82,#86,#88,#92));
    

The IfcUnitAssignment instance with the handle equal to 94 consists of one field; the instance field is an aggregate attribute with a set of instance identifiers. These identifiers refer to select data type instances:


#43= IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
#45= IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#46= IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
#50= IFCCONVERSIONBASEDUNIT(#48,.PLANEANGLEUNIT.,'DEGREE',#49);
#52= IFCSIUNIT(*,.MASSUNIT.,.KILO.,.GRAM.);
#55= IFCDERIVEDUNIT((#53,#54),.MASSDENSITYUNIT.,$);
#57= IFCSIUNIT(*,.TIMEUNIT.,$,.SECOND.);
#58= IFCSIUNIT(*,.FREQUENCYUNIT.,$,.HERTZ.);
#60= IFCSIUNIT(*,.THERMODYNAMICTEMPERATUREUNIT.,$,.DEGREE_CELSIUS.);
#64= IFCDERIVEDUNIT((#61,#62,#63),.THERMALTRANSMITTANCEUNIT.,$);
#69= IFCDERIVEDUNIT((#67,#68),.VOLUMETRICFLOWRATEUNIT.,$);
#71= IFCSIUNIT(*,.ELECTRICCURRENTUNIT.,$,.AMPERE.);
#72= IFCSIUNIT(*,.ELECTRICVOLTAGEUNIT.,$,.VOLT.);
#73= IFCSIUNIT(*,.POWERUNIT.,$,.WATT.);
#74= IFCSIUNIT(*,.FORCEUNIT.,.KILO.,.NEWTON.);
#75= IFCSIUNIT(*,.ILLUMINANCEUNIT.,$,.LUX.);
#76= IFCSIUNIT(*,.LUMINOUSFLUXUNIT.,$,.LUMEN.);
#77= IFCSIUNIT(*,.LUMINOUSINTENSITYUNIT.,$,.CANDELA.);
#82= IFCDERIVEDUNIT((#78,#79,#80,#81),.USERDEFINED.,'Luminous Efficacy');
#86= IFCDERIVEDUNIT((#84,#85),.LINEARVELOCITYUNIT.,$);
#92= IFCDERIVEDUNIT((#89,#90,#91),.USERDEFINED.,'Friction Loss');
    

To read and extract specific values from these aggregates:

  1. Get the application instance from the model by using the _sdaiGetEntityById() function call and check the result:
    
    SdaiAppInstance applicationInstance = _sdaiGetEntityById(model, 94);
    if ((applicationInstance == NULL) || (sdaiErrorQuery() != sdaiNO_ERR))
      return;
            
  2. Get access to the attribute with the name "units" with the sdaiGetAttrBN() function call; then request the number of members in the aggregate by calling the sdaiGetMemberCount() function:
    
    SdaiAggr  aggregate = NULL;
    if (sdaiGetAttrBN(applicationInstance, "units", sdaiAGGR, &aggregate) == NULL)
      return;
      
    if (sdaiGetMemberCount(aggregate) <= 0)
      return;
            
  3. Iterate the aggregate attribute items using iterator-related functions:
    
    SdaiIterator aggregateIterator = sdaiCreateIterator(aggregate);
    if (sdaiErrorQuery() != sdaiNO_ERR)
      return;
      
    for (sdaiBeginning(aggregateIterator); sdaiNext(aggregateIterator);)
    {
      SdaiADB adbToGet = sdaiCreateEmptyADB();
    
      if (sdaiGetAggrByIterator(aggregateIterator, sdaiADB, &adbToGet ) == NULL)
        return;
    
      SdaiInstance  instanceFromAdb = NULL;
      if (sdaiGetADBValue(adbToGet, sdaiINSTANCE, &instanceFromAdb ) == NULL)
        return;
    
      sdaiDeleteADB(adbToGet);
    
      SdaiInstance  instanceFromAdbSimpleGet = NULL;
      if (sdaiGetAggrByIterator(aggregateIterator, sdaiINSTANCE, &instanceFromAdbSimpleGet ) == NULL)
        return;
        
      if ((instanceFromAdb != instanceFromAdbSimpleGet) || (sdaiErrorQuery() != sdaiNO_ERR))
        return;
    }
            

    Inside the cycle through the items, an empty instance of the attribute data block is created (the sdaiCreateEmptyADB() function). The pointer to the created ADB object is passed to the sdaiGetAggrByIterator() function, which fills it with the appropriate data. To extract data contained in the attribute data block, use the sdaiGetADBValue() function.

    When the ADB instance is not needed anymore, delete it with an sdaiDeleteADB() function call to avoid memory leaks.

    The more simple way to get an attribute data block value from the aggregate is to pass a pointer to the desired instance to the sdaiGetAggrByIterator() function, and the function returns a valid value if the value of the attribute data block can be converted to the passed instance type. The last condition in the iterating cycle checks whether the conversion is successful.

Work with Nested Aggregates

This section describes how to read data from an aggregate attribute that contains an array of other aggregate attributes. Assume that an .ifc file contains the following application instance:


#1277= IFCRATIONALBSPLINESURFACEWITHKNOTS(
  3,1, 
      
  (
    (#1249,#1251), (#1253,#1255), (#1257,#1259), (#1261,#1263), (#1265,#1267), (#1269,#1271), (#1273,#1275)
  ), 
      
  .RULED_SURF.,.F.,.F.,.U.,(4,1,1,1,4),(2,2),(0.,0.25,0.5,0.75,1.),(0.,1.),
  .UNSPECIFIED., 
      
  (
    (1.,1.),(1.,1.),(1.,1.),(1.,1.),(1.,1.),(1.,1.),(1.,1.)
  )
    
);
    

This instance contains two-dimensional aggregates (highlighted with bold text). Below you can see how to read the first aggregate item from each two-dimensional aggregate.

  1. Get the appropriate parent instance with the _sdaiGetEntityById() function:
    
    SdaiAppInstance applicationInstance = _sdaiGetEntityById(model, 1277);
    if (applicationInstance == NULL) || (sdaiErrorQuery() != sdaiNO_ERR)
      return;
            
  2. Get the instance with the name "controlpointslist" and check the result:
    
    SdaiAggr  aggregate2dControlPointsList = NULL;
    if (sdaiGetAttrBN(applicationInstance, "controlpointslist", sdaiAGGR, &aggregate2dControlPointsList ) == NULL) 
      return;
      
    if (sdaiErrorQuery() != sdaiNO_ERR)
      return;
            
  3. Retrieve the child aggregate attribute with the index value equal to zero, from the control points list with the sdaiGetAggrByIndex() function call:
    
    SdaiAggr  aggregateChild = NULL;
    if (
        (sdaiGetAggrByIndex(aggregate2dControlPointsList, 0, sdaiAGGR, &aggregateChild ) == NULL) 
        || 
        (sdaiErrorQuery() != sdaiNO_ERR)
       )
    {
      return;
    }
            
  4. Read the first two child aggregates and check whether you have read the correct data. In the .ifc file fragment above, you can see that the first two aggregates have identifiers equal to 1249 and 1251 respectively. These values are used for checking whether the correct attributes are read.
    
    SdaiAppInstance  childAggrAppInstnce = NULL;
    if  (
          (sdaiGetAggrByIndex (aggregateChild, 0, sdaiINSTANCE, &childAggrAppInstnce ) == NULL)
          ||
          (_sdaiGetEntityId(childAggrAppInstnce) != 1249)
          ||
          (sdaiErrorQuery() != sdaiNO_ERR)
        )
    {
      return;
    }
    
    SdaiAppInstance  childAggrAppInstnce = NULL;
    if  (
          (sdaiGetAggrByIndex (aggregateChild, 1, sdaiINSTANCE, &childAggrAppInstnce ) == NULL)
          ||
          (_sdaiGetEntityId(childAggrAppInstnce) != 1251)
          ||
          (sdaiErrorQuery() != sdaiNO_ERR)
        )
    {
      return;
    }
            
  5. Another 2D aggregate has the name "weightsdata". The next code fragment illustrates how to get access to the aggregate contents without using the ADB functionality. First, get this aggregate with the appropriate name from the application instance. Then extract a nested aggregate.
    
    SdaiAggr  aggregate2dWeightsData = NULL;
    if ((sdaiGetAttrBN(applicationInstance, "weightsdata", sdaiAGGR, &aggregate2dWeightsData ) == NULL) || (sdaiErrorQuery() != sdaiNO_ERR))
      return;
    
    if ((sdaiGetAggrByIndex(aggregate2dWeightsData, 0, sdaiAGGR, &aggregateChild ) == NULL) || (sdaiErrorQuery() != sdaiNO_ERR))
      return;
            

    After getting the nested aggregate, call the sdaiGetAggrByIndex() function to get the coordinates included in the aggregate and check the result:

    
    SdaiReal  childAggrReal = NULL;
    
    // get and check the first coordinate from the aggregate
    if (
        (sdaiGetAggrByIndex(aggregateChild, 0, sdaiREAL, &childAggrReal ) == NULL)
        || (!OdEqual(childAggrReal, 1.))
        || (sdaiErrorQuery() != sdaiNO_ERR)
       )
    {
      return;
    }
    
    // get and check the second coordinate from the aggregate
    if (
        (sdaiGetAggrByIndex(aggregateChild, 0, sdaiREAL, &childAggrReal ) == NULL)
        || (!OdEqual(childAggrReal, 1.))
        || (sdaiErrorQuery() != sdaiNO_ERR)
       )
    {
      return;
    }
            

See Also

Work with Sets of Instances

Work with Attributes

Copyright © 2002 – 2021. Open Design Alliance. All rights reserved.