From 9c821dadc449fafd2a74d57d43f12734a23c15cc Mon Sep 17 00:00:00 2001 From: Jan Brouwer Date: Sat, 30 Mar 2024 09:20:05 +0100 Subject: [PATCH] exclude IFC classifications from IfcClassification creation --- .../lib/lib_ifc/PropertyReader.rb | 163 +++++++++--------- src/bt_ifcmanager/settings.rb | 60 ++++--- 2 files changed, 121 insertions(+), 102 deletions(-) diff --git a/src/bt_ifcmanager/lib/lib_ifc/PropertyReader.rb b/src/bt_ifcmanager/lib/lib_ifc/PropertyReader.rb index 5695e60..1b76506 100644 --- a/src/bt_ifcmanager/lib/lib_ifc/PropertyReader.rb +++ b/src/bt_ifcmanager/lib/lib_ifc/PropertyReader.rb @@ -52,36 +52,36 @@ def initialize(ifc_model, ifc_entity, entity_dict, instance_class = nil) @ifc_dict = entity_dict[ifc_version].attribute_dictionaries if entity_dict && entity_dict[ifc_version] @entity_dict = entity_dict @propertyset_names = [] - if @ifc_dict - # split attributes from properties - # First get property names - # names = attr_dict.map(&:name) - names = @ifc_dict.map { |x| x.name } - names -= UNUSED_DICTS # filter out unwanted dictionaries - ifc_entity_attributes = ifc_entity.attributes.map { |x| x.to_s } - @attributes = names & ifc_entity_attributes - - # Skip IfcProduct-only attributes for IfcTypeProduct - all_attributes = if instance_class - instance_class_attributes = instance_class.attributes.map { |x| x.to_s } - names & (ifc_entity_attributes + instance_class_attributes).uniq - else - @attributes - end - - @propertyset_names = names - all_attributes - end + return unless @ifc_dict + + # split attributes from properties + # First get property names + # names = attr_dict.map(&:name) + names = @ifc_dict.map { |x| x.name } + names -= UNUSED_DICTS # filter out unwanted dictionaries + ifc_entity_attributes = ifc_entity.attributes.map { |x| x.to_s } + @attributes = names & ifc_entity_attributes + + # Skip IfcProduct-only attributes for IfcTypeProduct + all_attributes = if instance_class + instance_class_attributes = instance_class.attributes.map { |x| x.to_s } + names & (ifc_entity_attributes + instance_class_attributes).uniq + else + @attributes + end + + @propertyset_names = names - all_attributes end # Set the IFC entity attributes def set_attributes - if @attributes - i = 0 - while i < @attributes.length - name = @attributes[i] - value = set_attribute(@ifc_dict[name]) - i += 1 - end + return unless @attributes + + i = 0 + while i < @attributes.length + name = @attributes[i] + value = set_attribute(@ifc_dict[name]) + i += 1 end end @@ -105,13 +105,14 @@ def add_propertysets end def add_classifications - if IfcManager::Settings.export_classifications && schema_types = @entity_dict['AppliedSchemaTypes'] - schema_types.each do |classification_name, classification_value| - # (?) exclude ALL IFC classifications? - unless Settings.ifc_version == classification_name - @ifc_model.classifications.add_classification_to_entity(@ifc_entity, classification_name, - classification_value, @entity_dict[classification_name]) - end + unless IfcManager::Settings.export_classifications && schema_types = @entity_dict['AppliedSchemaTypes'] + return + end + + schema_types.each do |classification_name, classification_value| + unless Settings.ifc_version_names.include?(classification_name) + @ifc_model.classifications.add_classification_to_entity(@ifc_entity, classification_name, + classification_value, @entity_dict[classification_name]) end end end @@ -120,18 +121,20 @@ def add_classifications # if defined in settings attributes def add_sketchup_definition_properties(ifc_model, ifc_entity, sketchup, type_properties = false) attributes = ifc_model.options[:attributes] - if attributes.include?(DEFINITION_SET_NAME) && (sketchup.attribute_dictionaries && (attr_dict = sketchup.attribute_dictionaries[DEFINITION_SET_NAME])) && propertyset = get_propertyset(attr_dict) - if type_properties - if ifc_entity.haspropertysets - ifc_entity.haspropertysets.add(propertyset) - else - ifc_entity.haspropertysets = IfcManager::Types::Set.new([propertyset]) - end + unless attributes.include?(DEFINITION_SET_NAME) && (sketchup.attribute_dictionaries && (attr_dict = sketchup.attribute_dictionaries[DEFINITION_SET_NAME])) && propertyset = get_propertyset(attr_dict) + return + end + + if type_properties + if ifc_entity.haspropertysets + ifc_entity.haspropertysets.add(propertyset) else - IfcRelDefinesByPropertiesBuilder.build(@ifc_model) do |builder| - builder.set_relatingpropertydefinition(propertyset) - builder.add_related_object(ifc_entity) - end + ifc_entity.haspropertysets = IfcManager::Types::Set.new([propertyset]) + end + else + IfcRelDefinesByPropertiesBuilder.build(@ifc_model) do |builder| + builder.set_relatingpropertydefinition(propertyset) + builder.add_related_object(ifc_entity) end end end @@ -167,7 +170,7 @@ def set_attribute(attr_dict) # Check if IFC type is set, otherwise use basic types ifc_value ||= get_ifc_property_value(value, property.attribute_type) - return @ifc_entity.send("#{name.downcase}=", ifc_value) if ifc_value + @ifc_entity.send("#{name.downcase}=", ifc_value) if ifc_value end # Creates PropertySet if there are any properties to export @@ -262,11 +265,11 @@ def get_propertyset(attr_dict) end def add_propertyset(attr_dict) - if propertyset = get_propertyset(attr_dict) - IfcRelDefinesByPropertiesBuilder.build(@ifc_model) do |builder| - builder.set_relatingpropertydefinition(propertyset) - builder.add_related_object(@ifc_entity) - end + return unless propertyset = get_propertyset(attr_dict) + + IfcRelDefinesByPropertiesBuilder.build(@ifc_model) do |builder| + builder.set_relatingpropertydefinition(propertyset) + builder.add_related_object(@ifc_entity) end end @@ -374,40 +377,40 @@ def initialize(attr_dict) # When no value in first level than look in the second level of attribute dictionaries # these next level attribute dictionaries normally have an IFC type as name # like: path = ["IFC 2x3", "IfcWindow", "Name", "IfcLabel"] - if !value && attr_dict.attribute_dictionaries - value_dicts = attr_dict.attribute_dictionaries - names = value_dicts.map { |x| x.name.to_sym } - names -= UNUSED_DICTS # filter out unwanted dictionaries + return unless !value && attr_dict.attribute_dictionaries - # there should be only one dictionary left - if ifc_type_name = names.first - value_dict = attr_dict.attribute_dictionaries[ifc_type_name.to_s] - @value = value_dict['value'] - @attribute_type = value_dict['attribute_type'] - @options = value_dict['options'] + value_dicts = attr_dict.attribute_dictionaries + names = value_dicts.map { |x| x.name.to_sym } + names -= UNUSED_DICTS # filter out unwanted dictionaries - # Check for IFC type - if ifc_type_name[0].upcase == ifc_type_name[0] && IfcManager.const_defined?(ifc_type_name) - @ifc_type = IfcManager.const_get(ifc_type_name) - end + # there should be only one dictionary left + return unless ifc_type_name = names.first - # Sometimes the value is even nested a level deeper - # like: path = ["IFC 2x3", "IfcWindow", "OverallWidth", "IfcPositiveLengthMeasure", "IfcLengthMeasure"] - # @todo: This deepest level does not contain the ifc_type we need! - if !@value && value_dict.attribute_dictionaries - subtype_dicts = value_dict.attribute_dictionaries - names = subtype_dicts.map { |x| x.name } - names -= UNUSED_DICTS # filter out unwanted dictionaries - - # there should be only one dictionary left - if ifc_subtype_name = names.first - subtype_dict = subtype_dicts[ifc_subtype_name] - @value = subtype_dict['value'] - @options = subtype_dict['options'] - end - end - end + value_dict = attr_dict.attribute_dictionaries[ifc_type_name.to_s] + @value = value_dict['value'] + @attribute_type = value_dict['attribute_type'] + @options = value_dict['options'] + + # Check for IFC type + if ifc_type_name[0].upcase == ifc_type_name[0] && IfcManager.const_defined?(ifc_type_name) + @ifc_type = IfcManager.const_get(ifc_type_name) end + + # Sometimes the value is even nested a level deeper + # like: path = ["IFC 2x3", "IfcWindow", "OverallWidth", "IfcPositiveLengthMeasure", "IfcLengthMeasure"] + # @todo: This deepest level does not contain the ifc_type we need! + return unless !@value && value_dict.attribute_dictionaries + + subtype_dicts = value_dict.attribute_dictionaries + names = subtype_dicts.map { |x| x.name } + names -= UNUSED_DICTS # filter out unwanted dictionaries + + # there should be only one dictionary left + return unless ifc_subtype_name = names.first + + subtype_dict = subtype_dicts[ifc_subtype_name] + @value = subtype_dict['value'] + @options = subtype_dict['options'] end end end diff --git a/src/bt_ifcmanager/settings.rb b/src/bt_ifcmanager/settings.rb index b5ae878..8b69228 100644 --- a/src/bt_ifcmanager/settings.rb +++ b/src/bt_ifcmanager/settings.rb @@ -23,24 +23,25 @@ # project/site/building/storeys # location # export: -# ifc_entities: false, # include IFC entity types given in array, like ["IfcWindow", "IfcDoor"], false means all -# hidden: false, # include hidden sketchup objects -# attributes: [], # include specific attribute dictionaries given in array as IfcPropertySets, like ['SU_DefinitionSet', 'SU_InstanceSet'], false means all -# classifications: true, # add all SketchUp classifications -# layers: true, # create IfcPresentationLayerAssignments -# materials: true, # create IfcMaterials -# colors: true, # create IfcStyledItems -# geometry: 'Brep' # ['Brep','Tessellation',false] -# fast_guid: false, # create simplified guids -# dynamic_attributes: false, # export dynamic component data -# open_file: false, # open created file in given/default application -# mapped_items: true, # Export IFC mapped items -# model_axes: true # Export using model axes instead of Sketchup internal origin -# textures: false # Add textures -# double_sided_faces: false # Add double sided faces +# ifc_entities: false, # include IFC entity types given in array, like ["IfcWindow", "IfcDoor"], false means all +# hidden: false, # include hidden sketchup objects +# attributes: [], # include specific attribute dictionaries given in array as IfcPropertySets, like ['SU_DefinitionSet', 'SU_InstanceSet'], false means all +# classifications: true, # add all SketchUp classifications +# layers: true, # create IfcPresentationLayerAssignments +# materials: true, # create IfcMaterials +# colors: true, # create IfcStyledItems +# geometry: 'Brep' # ['Brep','Tessellation',false] +# fast_guid: false, # create simplified guids +# dynamic_attributes: false, # export dynamic component data +# open_file: false, # open created file in given/default application +# mapped_items: true, # Export IFC mapped items +# classification_suffix: true # Add ' Classification' suffix to all classification for Revit compatibility +# model_axes: true # Export using model axes instead of Sketchup internal origin +# textures: false # Add textures +# double_sided_faces: false # Add double sided faces # load: -# classifications: [], # ["NL-SfB 2005, tabel 1", "DIN 276-1"] -# default_materials: false # {'beton'=>[142, 142, 142],'hout'=>[129, 90, 35],'staal'=>[198, 198, 198],'gips'=>[255, 255, 255],'zink'=>[198, 198, 198],'hsb'=>[204, 161, 0],'metselwerk'=>[102, 51, 0],'steen'=>[142, 142, 142],'zetwerk'=>[198, 198, 198],'tegel'=>[255, 255, 255],'aluminium'=>[198, 198, 198],'kunststof'=>[255, 255, 255],'rvs'=>[198, 198, 198],'pannen'=>[30, 30, 30],'bitumen'=>[30, 30, 30],'epdm'=>[30, 30, 30],'isolatie'=>[255, 255, 50],'kalkzandsteen'=>[255, 255, 255],'metalstud'=>[198, 198, 198],'gibo'=>[255, 255, 255],'glas'=>[204, 255, 255],'multiplex'=>[255, 216, 101],'cementdekvloer'=>[198, 198, 198]} +# classifications: [], # ["NL-SfB 2005, tabel 1", "DIN 276-1"] +# default_materials: false # {'beton'=>[142, 142, 142],'hout'=>[129, 90, 35],'staal'=>[198, 198, 198],'gips'=>[255, 255, 255],'zink'=>[198, 198, 198],'hsb'=>[204, 161, 0],'metselwerk'=>[102, 51, 0],'steen'=>[142, 142, 142],'zetwerk'=>[198, 198, 198],'tegel'=>[255, 255, 255],'aluminium'=>[198, 198, 198],'kunststof'=>[255, 255, 255],'rvs'=>[198, 198, 198],'pannen'=>[30, 30, 30],'bitumen'=>[30, 30, 30],'epdm'=>[30, 30, 30],'isolatie'=>[255, 255, 50],'kalkzandsteen'=>[255, 255, 255],'metalstud'=>[198, 198, 198],'gibo'=>[255, 255, 255],'glas'=>[204, 255, 255],'multiplex'=>[255, 216, 101],'cementdekvloer'=>[198, 198, 198]} require 'yaml' require 'cgi' @@ -58,6 +59,7 @@ module Settings attr_reader :ifc_classification, :ifc_classifications, + :ifc_version_names, :active_classifications, :common_psets, :export_classifications @@ -66,6 +68,7 @@ module Settings @common_psets = true @settings_file = File.join(PLUGIN_PATH, 'settings.yml') @ifc_classifications = {} + @ifc_version_names = [] # classifications shown in properties window @active_classifications = {} @@ -175,7 +178,7 @@ def load_settings @export_model_axes = CheckboxOption.new( 'model_axes', "Export using model axes transformation", - @options[:export][:classification_suffix], + @options[:export][:model_axes], "Export using model axes instead of Sketchup internal origin" ) end @@ -232,6 +235,19 @@ def load_ifc_skc(ifc_classification) end end + # This method retrieves the name of a SketchUp Classification. + # + # @param skc_file_name [String] The SKC file name. + # @return [String, nil] The name of the classification file, or nil if an error occurs. + def get_skc_name(skc_file_name) + begin + reader = SKC.new(skc_file_name) + return reader.name + rescue StandardError + return nil + end + end + def set_ifc_classification(ifc_classification_name) @ifc_classification = ifc_classification_name @ifc_classifications[ifc_classification_name] = true @@ -249,13 +265,13 @@ def unset_ifc_classification(ifc_classification_name) def read_ifc_classifications @ifc_classifications = {} + @ifc_version_names = [] if @options[:load][:ifc_classifications].is_a? Hash @options[:load][:ifc_classifications].each_pair do |ifc_classification_name, load| - if load == true + @ifc_classifications[ifc_classification_name] = load + @ifc_version_names << get_skc_name(ifc_classification_name) + if load @ifc_classification = ifc_classification_name - @ifc_classifications[ifc_classification_name] = load - elsif load == false - @ifc_classifications[ifc_classification_name] = load end end end