99
1010
1111class IfcDiff ():
12- def __init__ (self , old_file , new_file , output_file ):
12+ def __init__ (self , old_file , new_file , output_file , inverse_classes = None ):
1313 self .old_file = old_file
1414 self .new_file = new_file
1515 self .output_file = output_file
1616 self .change_register = {}
1717 self .representation_ids = []
18+ self .inverse_classes = inverse_classes
1819
1920 def diff (self ):
2021 print ('# IFC Diff' )
2122 self .load ()
2223
23- old_elements = set (e .GlobalId for e in self .old .by_type ('IfcElement ' ))
24- new_elements = set (e .GlobalId for e in self .new .by_type ('IfcElement ' ))
24+ old_elements = set (e .GlobalId for e in self .old .by_type ('IfcProduct ' ))
25+ new_elements = set (e .GlobalId for e in self .new .by_type ('IfcProduct ' ))
2526
2627 self .deleted_elements = old_elements - new_elements
2728 self .added_elements = new_elements - old_elements
@@ -42,6 +43,9 @@ def diff(self):
4243 new_element = self .new .by_id (global_id )
4344 self .diff_element (old_element , new_element )
4445
46+ if self .inverse_classes :
47+ self .diff_element_inverse_relationships (old_element , new_element )
48+
4549 representation_id = self .get_representation_id (new_element )
4650 if representation_id in self .representation_ids :
4751 continue
@@ -81,6 +85,26 @@ def diff_element(self, old_element, new_element):
8185 if diff and new_element .GlobalId :
8286 self .change_register .setdefault (new_element .GlobalId , {}).update (diff )
8387
88+ def diff_element_inverse_relationships (self , old_element , new_element ):
89+ old_relationships_all = self .old .get_inverse (old_element )
90+ new_relationships_all = self .new .get_inverse (new_element )
91+ old_relationships = [x for x in old_relationships_all if x .is_a () in self .inverse_classes ]
92+ new_relationships = [x for x in new_relationships_all if x .is_a () in self .inverse_classes ]
93+
94+ diff = DeepDiff (old_relationships , new_relationships ,
95+ significant_digits = 2 , ignore_string_type_changes = True , ignore_numeric_type_changes = True ,
96+ exclude_regex_paths = [
97+ r'root.*id$' ,
98+ r'.*GlobalId.*' ,
99+ r'.*OwnerHistory.*' ,
100+ r'.*RelatedObjects.*' ,
101+ r'.*RelatingObject.*' ,
102+ r'.*RelatingDefinitions.*' ,
103+ r'.*RelatedObjectsType.*' , # Deprecated in IFC4 anyway
104+ ])
105+ if diff and new_element .GlobalId :
106+ self .change_register .setdefault (new_element .GlobalId , {}).update (diff )
107+
84108 def diff_element_geometry (self , old_element , new_element ):
85109 try :
86110 DeepDiff (old_element .ObjectPlacement , new_element .ObjectPlacement ,
@@ -126,8 +150,14 @@ def default(self, obj):
126150 type = str ,
127151 help = 'The JSON diff file to output. Defaults to diff.json' ,
128152 default = 'diff.json' )
153+ parser .add_argument (
154+ '-r' ,
155+ '--relationships' ,
156+ type = str ,
157+ help = 'A list of IFC classes to check in inverse relationships, like "IfcRelDefinesByProperties".' ,
158+ default = '' )
129159 args = parser .parse_args ()
130-
131- ifc_diff = IfcDiff (args .old , args .new , args .output )
160+
161+ ifc_diff = IfcDiff (args .old , args .new , args .output , args . relationships . split () )
132162 ifc_diff .diff ()
133163 ifc_diff .export ()
0 commit comments