Skip to content

SCL adoption in IfcOpenShell

aothms edited this page Dec 11, 2011 · 2 revisions

IfcOpenShell is a free open source LGPL IFC implementation. IFC is a soon-to-be ISO standard based on STEP, used to exchange building and construction data. IfcOpenShell works with a quick and dirty IFC-parser, but is now in the process of migrating to SCL in order to provide more robust STEP support.

Points of interest

  1. Lazy loading. IFC files can easily grow over 100mb in file size, the multidisciplinary nature of IFC makes that often only a subset of the file is relevant for a specific context, therefore the feasibility of bringing lazy loading to SCL could be investigated.
  2. Type checking. For the way IfcOpenShell works it is necessary to query for instances taking the inheritance graph into account that is defined in the EXPRESS schema.

Progress

  1. It seems STEPfile::ReadData1() and STEPfile::ReadData2() are already separate functions that are used to parse the p21 file. Perhaps it'd work to skip STEPfile::ReadData2(), but instead storing the istream::tellg() file offset in the Application_instance class and calling STEPfile::ReadInstance() after calling istream::seekg() when the Application_instance is requested.
  2. It'd be nice if InstMgr::GetApplication_instance() could be extended to also return subtypes of the requested keyword. The way this works now in IfcOpenShell is that when an entity is parsed it is stored in a std::map for each of its supertypes.

Benchmark program

To get a little acquainted with SCL I have written a small application that prints some information on walls (IfcWallStandardCase) in an Ifc2x3 file. The goal in mind was to somewhat emulate the steps needed to extract geometry.

Hopefully the program can be used to test the feasibility of implementing lazy loading in SCL.

extern void SchemaInit( class Registry & );
#include "scl_version_string.h"
#include <STEPfile.h>
#include <sdai.h>
#include <STEPattribute.h>
#include <ExpDict.h>
#include <Registry.h>
#include <errordesc.h>
#include <algorithm>
#include <string>
#include <unistd.h>

#include "../../../build/IFC2X3_TC1/SdaiIFC2X3.h"

int main( int argc, char * argv[] ) {

    if ( argc != 2 ) exit(1);

    Registry  registry( SchemaInit );
    InstMgr   instance_list;
    STEPfile  sfile( registry, instance_list, "", false );

    sfile.ReadExchangeFile( argv[1] );
    sfile.Error().PrintContents(cout);

    Severity readSev = sfile.Error().severity(); //otherwise, errors from reading will be wiped out by sfile.WriteExchangeFile()
    
    // Keeps track of the last processed wall id 
    int search_index = 0;
    
    // Loop over the IfcWallStandardCases in the file
    while ( true ) {
        SdaiIfcwallstandardcase* wall = (SdaiIfcwallstandardcase*)
            instance_list.GetApplication_instance("IfcWallStandardCase",search_index);
    
        if ( wall == ENTITY_NULL ) break;
        
        cout << "Wall #" << wall->StepFileId() << " " << wall->globalid_() << endl; 
        
        // Descend all the way to the corresponding IfcRepresentationItems
        SdaiIfcproductrepresentation* repr = wall->representation_();
        EntityAggregate* reps = repr->representations_();
        const int rep_count = reps->EntryCount();
        if ( rep_count ) {
            EntityNode* node = (EntityNode*) reps->GetHead();
            // Loop over the representations
            do {
                SdaiIfcrepresentation* r = (SdaiIfcrepresentation*) node->node;
                const std::string rid = r->representationidentifier_();
                // Only process the Body representation
                if ( rid == "'Body'" ) {
                    EntityAggregate* rep_items = r->items_();
                    const int item_count = rep_items->EntryCount();
                    // Loop over representation items
                    if ( item_count ) {
                        EntityNode* item_node = (EntityNode*) rep_items->GetHead();
                        do {
                            SdaiIfcrepresentationitem* i = (SdaiIfcrepresentationitem*) item_node->node;
                            // If the representation is a simple extrusion, print the height
                            if ( i->IsA( ifc2x3::e_ifcextrudedareasolid ) ) {
                                SdaiIfcextrudedareasolid* ex = (SdaiIfcextrudedareasolid*) i;
                                float depth = ex->depth_();
                                cout << "Height: " << depth << endl;
                            }
                        } while ( item_node = (EntityNode*) item_node->NextNode() );
                    }
                }
            } while ( node = (EntityNode*) node->NextNode() );
        }
        
        // judging by the function name I would expect this to work too,
        // but it returns the StepFileId() instead
        // search_index = instance_list.GetIndex(wall)+1;
        
        MgrNode* mnode = instance_list.FindFileId( wall->StepFileId() );
        search_index = instance_list.GetIndex( mnode ) + 1;
    }

}

Same program using the IfcOpenShell parser

#include "../ifcparse/IfcParse.h"

using namespace Ifc2x3;

int main(int argc, char** argv) {

    if ( argc != 2 ) {
        std::cout << "usage: IfcParseExamples <filename.ifc>" << std::endl;
        return 1;
    }

    // Redirect the output (both progress and log) to stdout
    Ifc::SetOutput(&std::cout,&std::cout);

    // Parse the IFC file provided in argv[1]
    if ( ! Ifc::Init(argv[1]) ) {
        std::cout << "Unable to parse .ifc file" << std::endl;
        return 1;
    }

    IfcWallStandardCase::list walls = Ifc::EntitiesByType<IfcWallStandardCase>();

    for ( IfcWallStandardCase::it it = walls->begin(); it != walls->end(); ++ it ) {
        
        const IfcWallStandardCase::ptr wall = *it;
        std::cout << "Wall #" << wall->entity->id() << " " << wall->GlobalId() << std::endl;
        
        IfcProductRepresentation::ptr product_rep = wall->Representation();
        
        IfcRepresentation::list reps = product_rep->Representations();
        
        for ( IfcRepresentation::it it2 = reps->begin(); it2 != reps->end(); ++it2 ) {
            const IfcRepresentation::ptr rep = *it2;
            const std::string rid = rep->RepresentationIdentifier();
            if ( rid == "Body" ) {
                IfcRepresentationItem::list rep_items = rep->Items();
                for ( IfcRepresentationItem::it it3 = rep_items->begin(); it3 != rep_items->end(); ++ it3 ) {
                    const IfcRepresentationItem::ptr rep_item = *it3;
                    if ( rep_item->is(IfcExtrudedAreaSolid::Class()) ) {
                        const IfcExtrudedAreaSolid::ptr ex = 
                            (IfcExtrudedAreaSolid::ptr) rep_item;
                        const float depth = ex->Depth();
                        std::cout << "Height: " << depth << std::endl;
                    }
                }
            }
            
        }
    }

}

Clone this wiki locally