Re: [scl-dev] How to get inverse relationship with IFC file

319 views
Skip to first unread message

Mark

unread,
Jun 27, 2012, 5:33:55 PM6/27/12
to scl...@googlegroups.com
Hi Guparan,

On Wed, Jun 27, 2012 at 11:08 AM, guparan <gup...@gmail.com> wrote:
Hi,

First, I don't know if here is the right place to post for help but I didn't found any SCL help forum elsewhere.

You're in the right place!
 
Developing an IFC Viewer/Editor, I'd like to use SCL (which permits easy editing and writing) but I have some problem with inverse relationship.

For example, I try to get the PropertySet of my SdaiIfcwindow. With this set, I will know Thermal properties, Fire rating, ...
I want so to get the IFCRELDEFINESBYPROPERTIES from my IFC file.

I tried to use the isdefinedby_() method but if I use the EntityAggregate returned (for example calling EntityAggregate::EntryCount()) , I get a segfault (apparently because of EntityAggregate::ShallowCopy()).

Could you provide a small example that causes the problem? Also, what platform are you on?


What am I doing wrong ?

You may not be - we've had to track down a number of segfaults, and there may be more.



Thank you for your help :)

Regards,
Mark 

Mark

unread,
Jun 28, 2012, 6:11:30 AM6/28/12
to scl...@googlegroups.com
Hi Guparan,

When I put your instances in a file and tried it, I got a number of errors about missing instances. Could you give me a file that is complete?

Regards
Mark

ERROR:  ENTITY #124 Ifcwindow
  ownerhistory :  Reference to non-existent ENTITY #2.
  objectplacement :  Reference to non-existent ENTITY #125.
  representation :  Reference to non-existent ENTITY #130.
ERROR in EXCHANGE FILE: incomplete instance #124.
ERROR:  ENTITY #131 Ifcrelfillselement
  ownerhistory :  Reference to non-existent ENTITY #2.
  relatingopeningelement :  Reference to non-existent ENTITY #97.
ERROR in EXCHANGE FILE: incomplete instance #131.
ERROR:  ENTITY #132 Ifcpropertyset
  ownerhistory :  Reference to non-existent ENTITY #2.
ERROR in EXCHANGE FILE: incomplete instance #132.
ERROR:  ENTITY #145 Ifcreldefinesbyproperties
  ownerhistory :  Reference to non-existent ENTITY #2.
ERROR in EXCHANGE FILE: incomplete instance #145.
ERROR:  ENTITY #146 Ifcelementquantity
  ownerhistory :  Reference to non-existent ENTITY #2.
ERROR in EXCHANGE FILE: incomplete instance #146.
ERROR:  ENTITY #149 Ifcreldefinesbyproperties
  ownerhistory :  Reference to non-existent ENTITY #2.
ERROR in EXCHANGE FILE: incomplete instance #149.


On Thu, Jun 28, 2012 at 3:26 AM, guparan <gup...@gmail.com> wrote:
Hi,

I'm on a Linux xubuntu 3.2.0-25-generic, using Qt 4.8.1.
My problem has changed a little. There is no more segfault but I still can't get relations where they should be.
Here is a small example concerning a window.

The interesting part in my IFC file :
#124 = IFCWINDOW('0LV8Pid0X3IA3jJLVDPidY', #2, 'Window xyz', 'Description of Window', $, #125, #130, $, 1.400, 7.500E-1);
#131 = IFCRELFILLSELEMENT('1CDlLMVMv1qw1giUXpQgxI', #2, $, $, #97, #124);

#132 = IFCPROPERTYSET('0fhz_bHU54xB$tXHjHPUZl', #2, 'Pset_WindowCommon', $, (#133, #134, #135, #136, #137, #138, #139, #140, #141, #142, #143, #144));
#133 = IFCPROPERTYSINGLEVALUE('Reference', 'Reference', IFCTEXT(''), $);
#134 = IFCPROPERTYSINGLEVALUE('FireRating', 'FireRating', IFCTEXT(''), $);
#135 = IFCPROPERTYSINGLEVALUE('AcousticRating', 'AcousticRating', IFCTEXT(''), $);
#136 = IFCPROPERTYSINGLEVALUE('SecurityRating', 'SecurityRating', IFCTEXT(''), $);
#137 = IFCPROPERTYSINGLEVALUE('IsExternal', 'IsExternal', IFCBOOLEAN(.T.), $);
#138 = IFCPROPERTYSINGLEVALUE('Infiltration', 'Infiltration', IFCBOOLEAN(.F.), $);
#139 = IFCPROPERTYSINGLEVALUE('ThermalTransmittance', 'ThermalTransmittance', IFCREAL(2.400E-1), $);
#140 = IFCPROPERTYSINGLEVALUE('GlazingAresFraction', 'GlazingAresFraction', IFCREAL(7.000E-1), $);
#141 = IFCPROPERTYSINGLEVALUE('HandicapAccessible', 'HandicapAccessible', IFCBOOLEAN(.F.), $);
#142 = IFCPROPERTYSINGLEVALUE('FireExit', 'FireExit', IFCBOOLEAN(.F.), $);
#143 = IFCPROPERTYSINGLEVALUE('SelfClosing', 'SelfClosing', IFCBOOLEAN(.F.), $);
#144 = IFCPROPERTYSINGLEVALUE('SmokeStop', 'SmokeStop', IFCBOOLEAN(.F.), $);
#145 = IFCRELDEFINESBYPROPERTIES('2fHMxamlj5DvGvEKfCk8nj', #2, $, $, (#124), #132);

#146 = IFCELEMENTQUANTITY('0bB_7AP5v5OBZ90TDvo0Fo', #2, 'BaseQuantities', $, $, (#147, #148));
#147 = IFCQUANTITYLENGTH('Height', 'Height', $, 1.400);
#148 = IFCQUANTITYLENGTH('Width', 'Width', $, 7.500E-1);
#149 = IFCRELDEFINESBYPROPERTIES('0FmgI0DRX49OXL_$Wa2P1E', #2, $, $, (#124), #146);


The code I use :
void window_test ()
{
    Registry  registry( SchemaInit );
    InstMgr   instance_list;
    STEPfile  sfile( registry, instance_list, "", false );

    sfile.ReadExchangeFile( "simple_wall.ifc" );
    sfile.Error().PrintContents(cout);

    Severity readSev = sfile.Error().severity();

    SdaiIfcwindow* window = (SdaiIfcwindow*)
        instance_list.GetApplication_instance(124-1);

    if ( window == ENTITY_NULL ) { cout << "NULL" << endl; exit(1); }

    SDAI_String global_id = (SDAI_String) window->globalid_();
    cout << "Window #" << window->StepFileId() << " " << global_id.c_str() << endl;

    EntityAggregate* aggr = window->isdefinedby_();  // there is a lot a properties for my window
    if(aggr) cout << aggr->EntryCount() << endl;     // so aggr should be defined here
    else cout << "NOT DEFINED" << endl;              // but "NOT DEFINED" is printed
}

Thank you for your help.
Regards,
Guillaume

--
You received this message because you are subscribed to the Google Groups "STEPcode - Developers Mailing List" group.
To view this discussion on the web visit https://groups.google.com/d/msg/scl-dev/-/wtTW4WtNOyUJ.

To post to this group, send email to scl...@googlegroups.com.
To unsubscribe from this group, send email to scl-dev+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/scl-dev?hl=en.

guparan

unread,
Jun 28, 2012, 8:10:55 AM6/28/12
to scl...@googlegroups.com
Of course, I should have joined it before.
simple_wall.ifc

Mark

unread,
Jun 28, 2012, 8:42:09 PM6/28/12
to scl...@googlegroups.com
Ok, you aren't doing anything wrong; the inverse attribute isn't being initialized in the sdai lib.

I've created an issue for this: https://github.com/stepcode/stepcode/issues/193

A little information is present in the init function, as shown by `grep -n a_20Iisdefinedby build/IFC2X3_TC1/SdaiIFC2X3.init.cc` - but obviously that isn't enough.

What are you expecting the aggregate to contain? 

Regards
Mark

On Thu, Jun 28, 2012 at 8:10 AM, guparan <gup...@gmail.com> wrote:
Of course, I should have joined it before.

--
You received this message because you are subscribed to the Google Groups "STEPcode - Developers Mailing List" group.
To view this discussion on the web visit https://groups.google.com/d/msg/scl-dev/-/cpo1VzTLayAJ.

guparan

unread,
Jun 29, 2012, 3:52:48 AM6/29/12
to scl...@googlegroups.com
Hi,

In fact I don't understand why inverse attribute searching methods all return an EntityAggregate.

When I am doing window->isdefinedby_(), I'd like to get a SdaiIfcreldefines.
When I am doing window->hasassignements_(), I'd like to get a SdaiIfcrelassigns.
window->hasassociations_() ... SdaiIfcrelassociates
window->referencedby_() ... SdaiIfcrelassignstoproduct
window->containedinstructure_() ... SdaiIfcrelcontainedinspatialstructure
...

Why does it not work like this ?

Regards,
Guillaume.

Mark

unread,
Jun 29, 2012, 10:39:10 PM6/29/12
to scl...@googlegroups.com
I think it should work like that.

With exchange files, there are usually at least two ways of finding something.

It should be possible to find the inverse attributes using an inverse attribute list:

    const EntityDescriptor * ed = registry.FindEntity("ifcwindow");
    const Inverse_attributeList &ial = ed->InverseAttr();

However, that list is unpopulated as well, and I haven't yet found out why.

Regards
Mark 

Mark

unread,
Jul 1, 2012, 10:52:12 PM7/1/12
to scl...@googlegroups.com
Hi Guillame,

It took me a while but I have something that works now. You can't go from the entity with the INVERSE relationship to the entity referenced by that relationship; you must go the other way, searching through each SdaiIfcreldefines for the SdaiIfcwindow that you are interested in.

Using git, check out the 'mp/inverse_attr' branch. Then,

cd build/
cmake .. -DSCL_ENABLE_TESTING=ON
make tst_inverse_attr
bin/tst_inverse_attr ../test/p21/test_inverse_attr.p21

Note that the source (test/cpp/schema_specific/inverse_attr.cc) needs a lot of cleaning up, and the second method doesn't work yet (segfault)! The line below shows that the first method is working:
file id 1; name Object

I used a simplified schema (test/unitary_schemas/inverse_attr.exp), so the class names are different than what you use with IFC.

Regards
Mark

guparan

unread,
Jul 2, 2012, 11:32:18 AM7/2/12
to scl...@googlegroups.com
Hi Mark,

Thank you for your help, your code helped me a lot to get my properties.
I still have some difficulties in several points.

First, the first part of your code, in which you find inverse attributes of an Entity, does not work with my IFC example. There is no inverse attribute from my instance (window).
Then, I didn't find how to get the nominal value of my properties. I used attributes list (from my properties) to get them and I don't think it is a good way.

Here is my code :

int test_inverse()

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

    sfile.ReadExchangeFile( "simple_wall.ifc" );
    sfile.Error().PrintContents(cout);
    Severity readSev = sfile.Error().severity(); //otherwise, errors from reading will be wiped out by sfile.WriteExchangeFile()

    SdaiIfcwindow* instance = (SdaiIfcwindow*)
        instance_list.GetApplication_instance(124-1);
    if ( !instance || instance == ENTITY_NULL )
    {
        cout << "Null instance" << endl;
        exit(EXIT_FAILURE);
    }
    else cout << "instance #" << instance->StepFileId() << " (" << instance->name_().c_str() << ")" << endl;

    /* DOES NOT WORK */
    const EntityDescriptor * ed = instance->eDesc;
    InverseAItr inv_attr_itr( ed->InverseAttr() );
    const Inverse_attribute * ia;
    int j=0;
    while( (ia = inv_attr_itr.NextInverse_attribute()) != 0 ) j++;
    cout << "inv_attr_count = " << j << endl; // should not be zero
    Inverse_attributeList list = ed->InverseAttr();
    cout << "inv_attr_count = " << list.EntryCount() << endl; // should not be zero
    /* DOES NOT WORK */

    cout << "Properties of #" << instance->StepFileId() << " " << instance->EntityName() << " : " << endl;
    SdaiIfcreldefinesbyproperties* rdbp;
    int ent_id = 0;

    /* Inspect each IfcReldefinesbyproperties of my IFC file */
    while( ( rdbp = (SdaiIfcreldefinesbyproperties*)
             instance_list.GetApplication_instance("Ifcreldefinesbyproperties", ent_id) ) != 0 )
    {
        int i =  rdbp->StepFileId();
        if( i < ent_id ) {
            break;
        }
        ent_id = i;

        /* Keep only window properties */
        EntityAggregate * relObj = rdbp->relatedobjects_();
        if(!relObj || relObj->is_null()) exit(EXIT_FAILURE);
        EntityNode * en = (EntityNode *) relObj->GetHead();
        SdaiIfcwindow * window = dynamic_cast<SdaiIfcwindow *>(en->node);
        if(!window) continue;

        /* Search for property set */
        SdaiIfcpropertysetdefinition* psetdef = rdbp->relatingpropertydefinition_();
        SdaiIfcpropertyset* pset = dynamic_cast<SdaiIfcpropertyset*>(psetdef);
        if(!pset) continue;

        /* Look at the properties in property set */
        EntityAggregate* aggr = pset->hasproperties_();
        if(!aggr || aggr->is_null()) exit(EXIT_FAILURE);
        EntityNode* node = (EntityNode *) aggr->GetHead();
        do
        {
            SdaiIfcproperty* prop = (SdaiIfcproperty *) node->node;
            //prop->WriteValuePairs(cout << "  ");
            cout << "  " << prop->name_().c_str() << " = " << prop->attributes[2] << endl; // attribute[2] usage seems not a good choice
        } while( node = (EntityNode *)node->NextNode() );
    }
}

Regards,
Guillaume

Mark

unread,
Jul 5, 2012, 9:58:11 PM7/5/12
to scl...@googlegroups.com
Hi Guillaume

I haven't forgotten about you!

On Mon, Jul 2, 2012 at 11:32 AM, guparan <gup...@gmail.com> wrote:
Hi Mark,

Thank you for your help, your code helped me a lot to get my properties.
I still have some difficulties in several points.

First, the first part of your code, in which you find inverse attributes of an Entity, does not work with my IFC example. There is no inverse attribute from my instance (window).

It looks like they only show up for the entity for which they are declared in EXPRESS. I don't know whether this is by design or not. (Anybody?)
 
Then, I didn't find how to get the nominal value of my properties. I used attributes list (from my properties) to get them and I don't think it is a good way.

I'll have to look into this some more.

I also need to see if I can fix your original problem - that is, window->isdefinedby_() shouldn't return zero. With luck, I'll be able to do it when each instance is requested; this will save time if only a few instances are read from the file.

----------

I have added an option to the build system which should make your life easier. It isn't in master yet - it's in the branch mp/individual_schema_projects, and mp/inverse_attr would have to be rebased on top of it because it includes some necessary changes.

Configure with

cmake .. -DSCL_BUILD_SCHEMAS=../data/ifc2x3/IFC2X3_TC1.exp -DSC_SDAI_EXES_SRC=/path/to/simple_wall.cc

and an executable will be built using simple_wall.cc. It is bin/simple_wall_sdai_IFC2X3_TC1. Relative paths can be used, but an extra '../' must be prepended.
 

Regards
Mark

st...@costvision.com

unread,
Jul 9, 2012, 7:04:07 PM7/9/12
to scl...@googlegroups.com
On Thursday, July 5, 2012 7:58:11 PM UTC-6, mark wrote:


On Mon, Jul 2, 2012 at 11:32 AM, guparan <gup...@gmail.com> wrote:
Hi Mark,

Thank you for your help, your code helped me a lot to get my properties.
I still have some difficulties in several points.

First, the first part of your code, in which you find inverse attributes of an Entity, does not work with my IFC example. There is no inverse attribute from my instance (window).

It looks like they only show up for the entity for which they are declared in EXPRESS. I don't know whether this is by design or not. (Anybody?)

Not sure if this is the issue, but NIST said SCL provided a partial implementation of SDAI, and SCL was developed before SDAI was finalized.    10303-22:1998 (SDAI) section 13.1.2 Levels of expression evaluation for validation and derived attributes says Level 1 "consists of no support for ... Get Attribute of derived attributes, Get Attribute of inverse attributes declared in application schemas".   Maybe the cause of the issue is the level of conformance?   

Charlie

guparan

unread,
Jul 10, 2012, 3:34:48 AM7/10/12
to scl...@googlegroups.com
Hi Mark,

Sorry but I didn't understand the point of your build option.
What are the advantages ?

Regards,
Guillaume

Mark

unread,
Jul 10, 2012, 7:46:00 PM7/10/12
to scl...@googlegroups.com
On Tue, Jul 10, 2012 at 3:34 AM, guparan <gup...@gmail.com> wrote:
Hi Mark,

Sorry but I didn't understand the point of your build option.
What are the advantages ?


When you build an executable, I assume that you're either overwriting p21read.cc, modifying STEPcode's build system, or writing your own Makefile.

This option allows you to build one or more executables without doing any of that. There is one limitation - your code must be contained within a single file. I think it is possible to work around that (though I haven't tried it). The workaround is to use spaces as delimiters between files that are compiled into one executable, and to use semicolons to separate the files for different executables:
cmake .. -DSC_SDAI_EXES_SRC="/path/to/prog1.cc;/path/to/prog2_file1.cc /path/to/prog2_file2.cc"

If this option is used, p21read is not built unless p21read.cc is added to the list of source files.

Regards,
Guillaume


Regards
Mark 

Mark

unread,
Jul 15, 2012, 8:55:12 AM7/15/12
to scl...@googlegroups.com
On Mon, Jul 2, 2012 at 11:32 AM, guparan <gup...@gmail.com> wrote:
Hi Mark,

Thank you for your help, your code helped me a lot to get my properties.
I still have some difficulties in several points.

First, the first part of your code, in which you find inverse attributes of an Entity, does not work with my IFC example. There is no inverse attribute from my instance (window).

I have improved upon the inverse attribute test. Now, it looks for inverse attributes in the supertypes as well - stepcode/test/cpp/schema_specific/inverse_attr1.cc

Then, I didn't find how to get the nominal value of my properties. I used attributes list (from my properties) to get them and I don't think it is a good way.

You mean that you don't like using a constant for the index, i.e. attributes[2] ? For entities which don't have multiple inheritance, I think that the attribute index will always be the same unless the schema changes (i.e. IFC2x3 -> IFC2x4).

I added another example/test (test/cpp/schema_specific/attribute.cc) that searches for an attribute by name. Let me know whether it's what you are looking for or not.
 

Regards
Mark

--
You received this message because you are subscribed to the Google Groups "STEPcode - Developers Mailing List" group.
To view this discussion on the web visit https://groups.google.com/d/msg/scl-dev/-/HUtQSHs3zekJ.

guparan

unread,
Jul 16, 2012, 4:44:00 AM7/16/12
to scl...@googlegroups.com
Le dimanche 15 juillet 2012 14:55:12 UTC+2, mark a écrit :

I have improved upon the inverse attribute test. Now, it looks for inverse attributes in the supertypes as well - stepcode/test/cpp/schema_specific/inverse_attr1.cc

Did you test it with an IFC structure ? Because I still can't get any of my Ifcwindow relations (ifcpropertyset notably).
For the moment, I manage with the solution you suggested on 2012/07/02.

You mean that you don't like using a constant for the index, i.e. attributes[2] ? For entities which don't have multiple inheritance, I think that the attribute index will always be the same unless the schema changes (i.e. IFC2x3 -> IFC2x4).

You may be right !
 
I added another example/test (test/cpp/schema_specific/attribute.cc) that searches for an attribute by name. Let me know whether it's what you are looking for or not.

I'm not searching for attributes but relations. Since relations are not referenced in window declaration, I cannot use this trick (or I should search in each relation for my window id, which is already - and unfortunately - what I am doing).

Regards,
Guillaume

Mark

unread,
Jul 16, 2012, 9:14:00 PM7/16/12
to scl...@googlegroups.com
On Mon, Jul 16, 2012 at 4:44 AM, guparan <gup...@gmail.com> wrote:
Le dimanche 15 juillet 2012 14:55:12 UTC+2, mark a écrit :

I have improved upon the inverse attribute test. Now, it looks for inverse attributes in the supertypes as well - stepcode/test/cpp/schema_specific/inverse_attr1.cc

Did you test it with an IFC structure ? Because I still can't get any of my Ifcwindow relations (ifcpropertyset notably).
For the moment, I manage with the solution you suggested on 2012/07/02.

Oops, it only looks through the immediate supertypes; it also needs to look through their supertypes (and so on).

You mean that you don't like using a constant for the index, i.e. attributes[2] ? For entities which don't have multiple inheritance, I think that the attribute index will always be the same unless the schema changes (i.e. IFC2x3 -> IFC2x4).

You may be right !
 
I added another example/test (test/cpp/schema_specific/attribute.cc) that searches for an attribute by name. Let me know whether it's what you are looking for or not.

I'm not searching for attributes but relations. Since relations are not referenced in window declaration, I cannot use this trick (or I should search in each relation for my window id, which is already - and unfortunately - what I am doing).

OK. I'm thinking about adding a method to SDAI_Application_instance that initializes the inverse attribute pointers, or initializing all of them when an instance is first requested from the InstMgr. Either way will be slow unless we can find a way to avoid searching through all instances that might match the inverse attribute.
 

Regards,
Guillaume

Regards
Mark 

st...@costvision.com

unread,
Jul 18, 2012, 11:29:40 AM7/18/12
to scl...@googlegroups.com
Sounds like this is an use case where lazy loading as suggested by Thomas Krijnen could come into play.  


On Monday, July 16, 2012 7:14:00 PM UTC-6, mark wrote:
OK. I'm thinking about adding a method to SDAI_Application_instance that initializes the inverse attribute pointers, or initializing all of them when an instance is first requested from the InstMgr. Either way will be slow unless we can find a way to avoid searching through all instances that might match the inverse attribute.
 
Regards
Mark 

thomas krijnen

unread,
Jul 19, 2012, 2:54:37 PM7/19/12
to scl...@googlegroups.com
Hi, I hear my name.

In IfcOpenShell at parse time a map is populated that maps which instances reference each other to resolve the inverse attributes. So,
#1=A()
#2=B(#1)
#3=C(#1)
will result in a map:
 #1=>(#2,#3)

When A::getBs() is called this map is used in order not to have to iterate over all instances. This is independent of the express schema. It's not pretty but it (partly) works.

Kind regards,
Thomas

Mark

unread,
Jul 31, 2012, 6:49:21 PM7/31/12
to scl...@googlegroups.com
Hi Guillaume,

On Mon, Jul 16, 2012 at 9:14 PM, Mark <mpi...@gmail.com> wrote:


On Mon, Jul 16, 2012 at 4:44 AM, guparan <gup...@gmail.com> wrote:
Le dimanche 15 juillet 2012 14:55:12 UTC+2, mark a écrit :

I have improved upon the inverse attribute test. Now, it looks for inverse attributes in the supertypes as well - stepcode/test/cpp/schema_specific/inverse_attr1.cc

Did you test it with an IFC structure ? Because I still can't get any of my Ifcwindow relations (ifcpropertyset notably).
For the moment, I manage with the solution you suggested on 2012/07/02.

Oops, it only looks through the immediate supertypes; it also needs to look through their supertypes (and so on).

I've created another pull request, adding two recursive iterators. One for supertypes, one for subtypes. I think that the supertypes iterator will make this a lot easier.


Regards
Mark

 
Reply all
Reply to author
Forward
0 new messages