diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 414bfbf17..3281189a3 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -1208,6 +1208,47 @@ class _CommandComponent: FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() +def makeIfcSpreadsheet(obj=None): + import Spreadsheet + ifc_spreadsheet = FreeCAD.ActiveDocument.addObject('Spreadsheet::Sheet','IfcProperties') + ifc_spreadsheet.set('A1', translate("Arch","Category")) + ifc_spreadsheet.set('B1', translate("Arch","Key")) + ifc_spreadsheet.set('C1', translate("Arch","Type")) + ifc_spreadsheet.set('D1', translate("Arch","Value")) + ifc_spreadsheet.set('E1', translate("Arch","Unit")) + if obj : + if hasattr(obj,"IfcProperties"): + obj.IfcProperties = ifc_spreadsheet + return ifc_spreadsheet + else : + FreeCAD.Console.PrintWarning(translate("Arch", "The object have not IfcProperties attribute. Cancel spreadsheet creation for object : ") + obj.Label) + FreeCAD.ActiveDocument.removeObject(ifc_spreadsheet) + else: + return ifc_spreadsheet + +class _CommandIfcSpreadsheet: + "the Arch Schedule command definition" + def GetResources(self): + return {'Pixmap': 'Arch_Schedule', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_IfcSpreadsheet","Create IFC spreadsheet..."), + 'Accel': "I, P", + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_IfcSpreadsheet","Creates a spreadsheet to store ifc properties of an object.")} + + def IsActive(self): + return not FreeCAD.ActiveDocument is None + + def Activated(self): + sel = FreeCADGui.Selection.getSelection() + FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create IFC properties spreadsheet")) + FreeCADGui.addModule("Arch") + FreeCADGui.Control.closeDialog() + if sel: + for o in sel: + FreeCADGui.doCommand("Arch.makeIfcSpreadsheet(FreeCAD.ActiveDocument."+o.Name+")") + else : + FreeCADGui.doCommand("Arch.makeIfcSpreadsheet()") + FreeCAD.ActiveDocument.commitTransaction() + FreeCAD.ActiveDocument.recompute() if FreeCAD.GuiUp: FreeCADGui.addCommand('Arch_Add',_CommandAdd()) @@ -1222,3 +1263,4 @@ if FreeCAD.GuiUp: FreeCADGui.addCommand('Arch_Survey',_CommandSurvey()) FreeCADGui.addCommand('Arch_ToggleIfcBrepFlag',_ToggleIfcBrepFlag()) FreeCADGui.addCommand('Arch_Component',_CommandComponent()) + FreeCADGui.addCommand('Arch_IfcSpreadsheet',_CommandIfcSpreadsheet()) diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index de9a5705f..c547ca68b 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -299,6 +299,7 @@ class Component: obj.addProperty("App::PropertyLink","BaseMaterial","Material",translate("Arch","A material for this object")) obj.addProperty("App::PropertyEnumeration","Role","Arch",translate("Arch","The role of this object")) obj.addProperty("App::PropertyBool","MoveWithHost","Arch",translate("Arch","Specifies if this object must move together when its host is moved")) + obj.addProperty("App::PropertyLink","IfcProperties","Arch",translate("Arch","Custom IFC properties and attributes")) obj.Proxy = self self.Type = "Component" self.Subvolume = None diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index bbf20effd..44903c5a2 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -80,7 +80,7 @@ class ArchWorkbench(Workbench): "Arch_SelectNonSolidMeshes","Arch_RemoveShape", "Arch_CloseHoles","Arch_MergeWalls","Arch_Check", "Arch_IfcExplorer","Arch_ToggleIfcBrepFlag","Arch_3Views", - "Arch_Bimserver","Arch_Git"] + "Arch_Bimserver","Arch_Git","Arch_IfcSpreadsheet"] # draft tools self.drafttools = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc","Draft_Ellipse", diff --git a/src/Mod/Arch/Resources/ui/preferences-ifc.ui b/src/Mod/Arch/Resources/ui/preferences-ifc.ui index ed66245b5..999058c2d 100644 --- a/src/Mod/Arch/Resources/ui/preferences-ifc.ui +++ b/src/Mod/Arch/Resources/ui/preferences-ifc.ui @@ -7,7 +7,7 @@ 0 0 456 - 542 + 564 @@ -288,6 +288,26 @@ + + + + + + If checked each object will have their Ifc Properties stored in a spreadsheet object. + + + Import Ifc Properties in spreadsheet + + + ifcImportProperties + + + Mod/Arch + + + + + @@ -414,13 +434,13 @@
Gui/PrefWidgets.h
- Gui::PrefComboBox - QComboBox + Gui::PrefLineEdit + QLineEdit
Gui/PrefWidgets.h
- Gui::PrefLineEdit - QLineEdit + Gui::PrefComboBox + QComboBox
Gui/PrefWidgets.h
diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index dfadd45df..7dd5c3919 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -22,7 +22,7 @@ #*************************************************************************** __title__ = "FreeCAD IFC importer - Enhanced ifcopenshell-only version" -__author__ = "Yorik van Havre" +__author__ = "Yorik van Havre","Jonathan Wiedemann" __url__ = "http://www.freecadweb.org" import os,time,tempfile,uuid,FreeCAD,Part,Draft,Arch,math,DraftVecUtils @@ -124,7 +124,7 @@ def getPreferences(): global DEBUG, PREFIX_NUMBERS, SKIP, SEPARATE_OPENINGS global ROOT_ELEMENT, GET_EXTRUSIONS, MERGE_MATERIALS global MERGE_MODE_ARCH, MERGE_MODE_STRUCT, CREATE_CLONES - global FORCE_BREP + global FORCE_BREP, IMPORT_PROPERTIES p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") if FreeCAD.GuiUp and p.GetBool("ifcShowDialog",False): import FreeCADGui @@ -145,6 +145,7 @@ def getPreferences(): SKIP.append("IfcOpeningElement") CREATE_CLONES = p.GetBool("ifcCreateClones",True) FORCE_BREP = p.GetBool("ifcExportAsBrep",False) + IMPORT_PROPERTIES = p.GetBool("ifcImportProperties",False) def explore(filename=None): @@ -363,7 +364,7 @@ def insert(filename,docname,skip=[],only=[],root=None): additions = {} # { host:[child,...], ... } groups = {} # { host:[child,...], ... } # used in structural IFC subtractions = [] # [ [opening,host], ... ] - properties = {} # { host:[property, ...], ... } + properties = {} # { obj : { cat : [property, ... ], ... }, ... } colors = {} # { id:(r,g,b) } shapes = {} # { id:shaoe } only used for merge mode structshapes = {} # { id:shaoe } only used for merge mode @@ -379,8 +380,14 @@ def insert(filename,docname,skip=[],only=[],root=None): subtractions.append([r.RelatedOpeningElement.id(), r.RelatingBuildingElement.id()]) for r in ifcfile.by_type("IfcRelDefinesByProperties"): for obj in r.RelatedObjects: + if not obj.id() in properties : + properties[obj.id()] = {} + prop_by_category = {} + prop = [] if r.RelatingPropertyDefinition.is_a("IfcPropertySet"): - properties.setdefault(obj.id(),[]).extend([e.id() for e in r.RelatingPropertyDefinition.HasProperties]) + prop.extend([e.id() for e in r.RelatingPropertyDefinition.HasProperties]) + prop_by_category[r.RelatingPropertyDefinition.id()] = prop + properties[obj.id()].update(prop_by_category) for r in ifcfile.by_type("IfcRelAssociatesMaterial"): for o in r.RelatedObjects: mattable[o.id()] = r.RelatingMaterial.id() @@ -614,12 +621,40 @@ def insert(filename,docname,skip=[],only=[],root=None): # properties if pid in properties: - if hasattr(obj,"IfcAttributes"): + if IMPORT_PROPERTIES and hasattr(obj,"IfcProperties") : + ifc_spreadsheet = Arch.makeIfcSpreadsheet() + n=2 + for c in properties[pid].keys(): + o = ifcfile[c] + if DEBUG : print("propertyset Name",o.Name,type(o.Name)) + catname = o.Name + for p in properties[pid][c]: + l = ifcfile[p] + if l.is_a("IfcPropertySingleValue"): + if IMPORT_PROPERTIES : + if DEBUG : + print("property name",l.Name,type(l.Name)) + print("property NominalValue",l.NominalValue.is_a(),type(l.NominalValue.is_a())) + print("property NominalValue.wrappedValue",l.NominalValue.wrappedValue,type(l.NominalValue.wrappedValue)) + #print("l.NominalValue.Unit",l.NominalValue.Unit,type(l.NominalValue.Unit)) + ifc_spreadsheet.set(str('A'+str(n)), catname.encode("utf8")) + ifc_spreadsheet.set(str('B'+str(n)), l.Name.encode("utf8")) + ifc_spreadsheet.set(str('C'+str(n)), l.NominalValue.is_a()) + if l.NominalValue.is_a() in ['IfcLabel','IfcText','IfcIdentifier']: + ifc_spreadsheet.set(str('D'+str(n)), "'" + str(l.NominalValue.wrappedValue.encode("utf8"))) + else : + ifc_spreadsheet.set(str('D'+str(n)), str(l.NominalValue.wrappedValue)) + if hasattr(l.NominalValue,'Unit') : + ifc_spreadsheet.set(str('E'+str(n)), str(l.NominalValue.Unit)) + n += 1 + obj.IfcProperties = ifc_spreadsheet + elif hasattr(obj,"IfcAttributes"): a = obj.IfcAttributes - for p in properties[pid]: - o = ifcfile[p] - if o.is_a("IfcPropertySingleValue"): - a[o.Name.encode("utf8")] = str(o.NominalValue) + for c in properties[pid].keys(): + for p in properties[pid][c]: + l = ifcfile[p] + if l.is_a("IfcPropertySingleValue"): + a[l.Name.encode("utf8")] = str(l.NominalValue) obj.IfcAttributes = a # color @@ -944,35 +979,91 @@ def export(exportList,filename): ifcfile.createIfcRelVoidsElement(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'Subtraction','',product,prod2) # properties - if hasattr(obj,"IfcAttributes"): - props = [] - for key in obj.IfcAttributes: - if not (key in ["IfcUID","FlagForceBrep"]): - r = obj.IfcAttributes[key].strip(")").split("(") - if len(r) == 1: - tp = "IfcText" - val = r[0] - else: - tp = r[0] - val = "(".join(r[1:]) - val = val.strip("'") - val = val.strip('"') - if DEBUG: print " property ",key," : ",val.encode("utf8"), " (", str(tp), ")" - if tp in ["IfcLabel","IfcText","IfcIdentifier"]: - val = val.encode("utf8") - elif tp == "IfcBoolean": - if val == ".T.": - val = True + if hasattr(obj,"IfcProperties") or hasattr(obj,"IfcAttributes"): + if DEBUG : print(" add ifc properties") + if obj.IfcProperties: + if obj.IfcProperties.TypeId == 'Spreadsheet::Sheet': + sheet = obj.IfcProperties + propertiesDic = {} + categories = [] + n=2 + cell = True + while cell == True : + if hasattr(sheet,'A'+str(n)): + cat = sheet.get('A'+str(n)) + key = sheet.get('B'+str(n)) + tp = sheet.get('C'+str(n)) + if hasattr(sheet,'D'+str(n)): + val = sheet.get('D'+str(n)) else: - val = False - elif tp == "IfcInteger": - val = int(val) + val = '' + if isinstance(key, unicode): + key = key.encode("utf8") + else : + key = str(key) + tp = tp.encode("utf8") + if tp in ["IfcLabel","IfcText","IfcIdentifier"]: + val = val.encode("utf8") + elif tp == "IfcBoolean": + if val == 'True': + val = True + else: + val = False + elif tp == "IfcInteger": + val = int(val) + else: + val = float(val) + unit = None + #unit = sheet.get('E'+str(n)) + if cat in categories : + propertiesDic[cat].append({"key":key,"tp":tp,"val":val,"unit":unit}) + else: + propertiesDic[cat] = [{"key":key,"tp":tp,"val":val,"unit":unit}] + categories.append(cat) + n += 1 else: - val = float(val) - props.append(ifcfile.createIfcPropertySingleValue(str(key),None,ifcfile.create_entity(str(tp),val),None)) - if props: - pset = ifcfile.createIfcPropertySet(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'PropertySet',None,props) - ifcfile.createIfcRelDefinesByProperties(ifcopenshell.guid.compress(uuid.uuid1().hex),history,None,None,[product],pset) + cell = False + for cat in propertiesDic: + props = [] + for prop in propertiesDic[cat] : + if DEBUG : + print("key",prop["key"],type(prop["key"])) + print("tp",prop["tp"],type(prop["tp"])) + print("val",prop["val"],type(prop["val"])) + props.append(ifcfile.createIfcPropertySingleValue(prop["key"],None,ifcfile.create_entity(prop["tp"],prop["val"]),None)) + pset = ifcfile.createIfcPropertySet(ifcopenshell.guid.compress(uuid.uuid1().hex),history,cat,None,props) + ifcfile.createIfcRelDefinesByProperties(ifcopenshell.guid.compress(uuid.uuid1().hex),history,None,None,[product],pset) + elif obj.IfcAttributes: + props = [] + for key in obj.IfcAttributes: + if not (key in ["IfcUID","FlagForceBrep"]): + r = obj.IfcAttributes[key].strip(")").split("(") + if len(r) == 1: + tp = "IfcText" + val = r[0] + else: + tp = r[0] + val = "(".join(r[1:]) + val = val.strip("'") + val = val.strip('"') + if DEBUG: print " property ",key," : ",val.encode("utf8"), " (", str(tp), ")" + if tp in ["IfcLabel","IfcText","IfcIdentifier"]: + val = val.encode("utf8") + elif tp == "IfcBoolean": + if val == ".T.": + val = True + else: + val = False + elif tp == "IfcInteger": + val = int(val) + else: + val = float(val) + props.append(ifcfile.createIfcPropertySingleValue(str(key),None,ifcfile.create_entity(str(tp),val),None)) + if props: + pset = ifcfile.createIfcPropertySet(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'PropertySet',None,props) + ifcfile.createIfcRelDefinesByProperties(ifcopenshell.guid.compress(uuid.uuid1().hex),history,None,None,[product],pset) + else: + if DEBUG : print("no ifc properties to export") count += 1