Sample 02
In this sample, you will learn how to read the attributes of instances of different entities. Read and loop over the contents of aggregate attributes and list the coordinates of all six faces of a cube represented by IFC geometry.
Before reading this sample, you should run through Sample 01 and make sure you understand the basic operations of EDMsdk.
The complete package with resource files and source code is available from Getting Started with EDMsdk, but you may also download the source code of the sample below.
In the following, we will walk you through all the statements and explain them.
The preparations for this sample include the following statements
if (rstat = edmiDeleteDatabase (dbPath, dbName, dbPwd)) { if (rstat != edmiENOSUCHDATABASE) { printf("\nERROR: Failed to delete database", edmiGetErrorText(rstat)); goto err; } } if (rstat = edmiCreateDatabase (dbPath, dbName, dbPwd)) goto err; if (rstat = edmiOpenDatabase(dbPath, dbName, dbPwd)) goto err; if ((sessionId = sdaiOpenSession()) == 0) goto err; if (rstat = edmiCreateRepository(repositoryName, &repositoryId)) goto err; if (rstat = edmiDefineSchema(expressFile, expressDiagFile, schemaName, 0, &nWarnings, &nErrors)) goto err; if (rstat = edmiGetSchema(schemaName, &schemaId)) goto err; if (rstat = edmiImportStepFile(stepFile, stepDiagFile, repositoryName, modelName, schemaName, NULL, 0, &modelId, &sdaiErr)) goto err; if ((modelId = sdaiOpenModel(modelId, sdaiRO)) == 0) goto err;
The EDMdatabase now contains a population of the IFC4 Express schema in an EDMmodel named "cube". What we will do next is to list all the coordinates of the corners of the six sides of a cube. To understand this sample, we need to understand how the data is organized in the EDMmodel.
A cube is represented by an aggregate of six individual faces. Each cube is an instance of the entity IFCFACETEDBREP. The first thing we need to do is to look up all the instances of the entitry IFCFACETEDBREP. There may of course be any number of objects represented by instances of the IFCFACETEDBREP entity. Not only cubes, but in this sample, to not complicate things, we happen to know that there is just a single cube.
To look up all instances of the type IFCFACETEDBREP, we can do so by loop over all instances in its entity extent. An entity extent is an aggregate maintained automatically by EDMsix. When a new IFCFACETEDBREP object is created, it will automatically be added to its entity extent.
We can use the function sdaiGetEntityExtentBN() to read the aggregate of IFCFACETEDBREP objects
ifcFacetBrep_AggrId = sdaiGetEntityExtentBN(modelId, "IFCFACETEDBREP");
Note that the returned value is the id of the aggregate and not the aggregate it self. We must use this aggregate id to look up the aggregate elements. In most cases, we would loop over this aggregate, but since we know that there is only one element, we will just address it by its index, 0.
edmiGetAggrElement(ifcFacetBrep_AggrId, 0, sdaiINSTANCE, &ifcFacetBrep_Id);
What we have now is the identifier of the cube we are looking at. All the properties of the cube can be obtained through this "handle".
ENTITY ifcfacetedbrep; outer : ifcclosedshell; END_ENTITY ENTITY ifcclosedshell; cfsfaces : SET [1:?] OF ifcface; END_ENTITY;
We are only interested in the geometry, so we will concentrate on the relevant attributes. An extract from the IFC4 EXPRESS schema shows us where to look for the six faces. The cube identifier we have has an attribute named "outer" that will be an instance of type IFCCLOSEDSHELL. This instance in turn has an attribute named "cfsfaces", which is what we look for; an identifier of an aggregate with all the six faces. We use the function sdaiGetAttrBN() to traverse this path of instances and attributes.
sdaiGetAttrBN(ifcFacetBrep_Id, "OUTER", sdaiINSTANCE, &ifcClosedShell_Id); sdaiGetAttrBN(ifcClosedShell_Id, "CFSFACES", sdaiAGGR, &ifcFace_AggrId);
What we have now is the "handle" to the aggregate that contains all the six faces making up the cube. Each of the six faces is identified by an instance of the type IFCFACE. Again we will have to traverse through the instances and attributes that is defined by the IFC4 geometry. The Entities ant
ENTITY ifcface; bounds : SET [1:?] OF ifcfacebound; END_ENTITY; ENTITY ifcfacebound; bound : ifcloop; END_ENTITY; ENTITY ifcpolyloop; polygon : LIST [3:?] OF UNIQUE ifccartesianpoint; END_ENTITY; ENTITY ifccartesianpoint; coordinates : LIST [1:3] OF IFCLENGTHMEASURE; END_ENTITY;
for (faceNo = 0; faceNo < 6; faceNo++) { edmiGetAggrElement(ifcFace_AggrId, faceNo, sdaiINSTANCE, &ifcFace_Id); sdaiGetAttrBN(ifcFace_Id, "BOUNDS", sdaiAGGR, &ifcFaceBounds_AggrId); edmiGetAggrElement(ifcFaceBounds_AggrId, 0, sdaiINSTANCE, &ifcOuterBound_Id); sdaiGetAttrBN(ifcOuterBound_Id, "BOUND", sdaiINSTANCE, &ifcLoop_Id); sdaiGetAttrBN(ifcLoop_Id, "POLYGON", sdaiAGGR, &ifcCartesianPoint_AggrId); printf("\nFace No. %d: [", (faceNo+1)); for (pointNo = 0; pointNo < 4; pointNo++) { edmiGetAggrElement(ifcCartesianPoint_AggrId, pointNo, sdaiINSTANCE, &ifcCartesianPoint_Id); sdaiGetAttrBN(ifcCartesianPoint_Id, "COORDINATES", sdaiAGGR, &coordinates_AggrId); edmiReadAggrElements(coordinates_AggrId, 0, 3, &nElem, &type, NULL, &coordinates); printf(" (%6.1f, %6.1f, %6.1f) %s", coordinates[0], coordinates[1], coordinates[2], (pointNo<3)?"-":"]"); } }
The code block above shows that the traversing down to the individual points in a face is just a matter of using the same functions that we used to find the aggregate of faces. A successful execution of this sample shall result in the following output;
================================================================ Compilation result of EXPRESS Schema : IFC4 in source file : ./ifc4.exp ================================================================ 0 WARNINGS detected. 0 ERRORS detected. P7 P8 This Cube is represented by an aggregate of six *---------------* faces in a CUBE=IFCFACETEDBREP(F1,F2,F3,F4,F5,F6) /. /| Each face is represented by a polygon / . / | in an IFCFACEOUTERBOUND like; /P5. P6 / | *---------------* | F1 = IFCFACEOUTERBOUND(IFCPOLYLOOP(P1,P2,P3,P4)) | . | | F2 = IFCFACEOUTERBOUND(IFCPOLYLOOP(P1,P2,P5,P6)) | . | | F3 = IFCFACEOUTERBOUND(IFCPOLYLOOP(P2,P3,P6,P8)) | . | | | . | | and so on. | . P4 | | | *. .........|.. * P3 Below, this example will read and print the | . | / coordinates of all the six faces. | . | / The type graph from IFCFACETEDBREP to the |. |/ cubes set of four IFCCARTESIANPOINT is. *---------------* P1 P2 IFCFACETEDBREP.IFCCLOSEDSHELL.IFCFACE[6].IFCFACEBOUNDS[1].IFCLOOP.IFCCARTESIANPOINT[4] Face No. 1: [ (-500, -500, 0) | ( 500, -500, 0) | ( 500, 500, 0) | (-500, 500, 0) ] Face No. 2: [ (-500, -500, 0) | ( 500, -500, 0) | (-500, -500, 1000) | (-500, -500, 1000) ] Face No. 3: [ ( 500, -500, 0) | ( 500, 500, 0) | ( 500, 500, 1000) | (-500, 500, 1000) ] Face No. 4: [ (-500, 500, 0) | ( 500, 500, 0) | ( 500, 500, 1000) | (-500, 500, 1000) ] Face No. 5: [ (-500, -500, 0) | (-500, 500, 0) | (-500, 500, 1000) | (-500, -500, 1000) ] Face No. 6: [ ( 500, -500, 1000) | ( 500, -500, 1000) | ( 500, 500, 1000) | (-500, 500, 1000) ] ***** DONE *****
Check also the other samples in Getting Started with EDMsdk