Skip to content

Commit

Permalink
exclude IFC classifications from IfcClassification creation
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrouwerdigibase committed Mar 30, 2024
1 parent 7b171c6 commit 9c821da
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 102 deletions.
163 changes: 83 additions & 80 deletions src/bt_ifcmanager/lib/lib_ifc/PropertyReader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
60 changes: 38 additions & 22 deletions src/bt_ifcmanager/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -58,6 +59,7 @@ module Settings

attr_reader :ifc_classification,
:ifc_classifications,
:ifc_version_names,
:active_classifications,
:common_psets,
:export_classifications
Expand All @@ -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 = {}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 9c821da

Please sign in to comment.