Arch: Merge of PR #2259 - Fix ifc project
This commit is contained in:
@@ -43,6 +43,7 @@ if FreeCAD.GuiUp:
|
||||
from ArchWall import *
|
||||
from ArchFloor import *
|
||||
from ArchFence import *
|
||||
from ArchProject import *
|
||||
from ArchSite import *
|
||||
from ArchBuilding import *
|
||||
from ArchStructure import *
|
||||
|
||||
@@ -313,7 +313,7 @@ class CommandBuildingPart:
|
||||
|
||||
|
||||
|
||||
class BuildingPart:
|
||||
class BuildingPart(ArchIFC.IfcProduct):
|
||||
|
||||
|
||||
"The BuildingPart object"
|
||||
@@ -326,7 +326,7 @@ class BuildingPart:
|
||||
self.setProperties(obj)
|
||||
|
||||
def setProperties(self,obj):
|
||||
ArchIFC.setProperties(obj)
|
||||
ArchIFC.IfcProduct.setProperties(self, obj)
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Height" in pl:
|
||||
@@ -366,7 +366,7 @@ class BuildingPart:
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
|
||||
ArchIFC.onChanged(obj, prop)
|
||||
ArchIFC.IfcProduct.onChanged(self, obj, prop)
|
||||
|
||||
if prop == "Height":
|
||||
for child in obj.Group:
|
||||
|
||||
@@ -116,7 +116,7 @@ def addComponents(objectsList,host):
|
||||
if not isinstance(objectsList,list):
|
||||
objectsList = [objectsList]
|
||||
hostType = Draft.getType(host)
|
||||
if hostType in ["Floor","Building","Site","BuildingPart"]:
|
||||
if hostType in ["Floor","Building","Site","Project","BuildingPart"]:
|
||||
for o in objectsList:
|
||||
host.addObject(o)
|
||||
elif hostType in ["Wall","Structure","Window","Roof","Stairs","StructuralSystem","Panel","Component"]:
|
||||
@@ -744,7 +744,7 @@ def pruneIncluded(objectslist,strict=False):
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
if not (Draft.getType(obj) in ["Window","Clone","Pipe","Rebar"]):
|
||||
for parent in obj.InList:
|
||||
if parent.isDerivedFrom("Part::Feature") and not (Draft.getType(parent) in ["Space","Facebinder","Window","Roof","Clone","Site"]):
|
||||
if parent.isDerivedFrom("Part::Feature") and not (Draft.getType(parent) in ["Space","Facebinder","Window","Roof","Clone","Site","Project"]):
|
||||
if not parent.isDerivedFrom("Part::Part2DObject"):
|
||||
# don't consider 2D objects based on arch elements
|
||||
if hasattr(parent,"Host") and (parent.Host == obj):
|
||||
|
||||
@@ -133,22 +133,20 @@ def removeFromComponent(compobject,subobject):
|
||||
|
||||
|
||||
|
||||
class Component:
|
||||
|
||||
class Component(ArchIFC.IfcProduct):
|
||||
|
||||
"The default Arch Component object"
|
||||
|
||||
def __init__(self,obj):
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
Component.setProperties(self,obj)
|
||||
Component.setProperties(self, obj)
|
||||
self.Type = "Component"
|
||||
|
||||
def setProperties(self,obj):
|
||||
def setProperties(self, obj):
|
||||
|
||||
"Sets the needed properties of this object"
|
||||
|
||||
ArchIFC.setProperties(obj)
|
||||
ArchIFC.IfcProduct.setProperties(self, obj)
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Base" in pl:
|
||||
@@ -195,9 +193,8 @@ class Component:
|
||||
#self.MoveWithHost = False
|
||||
self.Type = "Component"
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
|
||||
Component.setProperties(self,obj)
|
||||
def onDocumentRestored(self, obj):
|
||||
Component.setProperties(self, obj)
|
||||
|
||||
def execute(self,obj):
|
||||
|
||||
@@ -210,24 +207,20 @@ class Component:
|
||||
obj.Shape = shape
|
||||
|
||||
def __getstate__(self):
|
||||
|
||||
# for compatibility with 0.17
|
||||
if hasattr(self,"Type"):
|
||||
return self.Type
|
||||
return "Component"
|
||||
|
||||
def __setstate__(self,state):
|
||||
|
||||
return None
|
||||
|
||||
def onBeforeChange(self,obj,prop):
|
||||
|
||||
if prop == "Placement":
|
||||
self.oldPlacement = FreeCAD.Placement(obj.Placement)
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
|
||||
ArchIFC.onChanged(obj, prop)
|
||||
def onChanged(self, obj, prop):
|
||||
ArchIFC.IfcProduct.onChanged(self, obj, prop)
|
||||
|
||||
if prop == "Placement":
|
||||
if hasattr(self,"oldPlacement"):
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD,Draft,ArchCommands, DraftVecUtils
|
||||
import FreeCAD,Draft,ArchCommands, DraftVecUtils, ArchIFC
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
@@ -121,7 +121,7 @@ Floor creation aborted.") + "\n"
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
class _Floor:
|
||||
class _Floor(ArchIFC.IfcProduct):
|
||||
|
||||
"The Floor object"
|
||||
|
||||
@@ -134,6 +134,7 @@ class _Floor:
|
||||
|
||||
def setProperties(self,obj):
|
||||
|
||||
ArchIFC.IfcProduct.setProperties(self, obj)
|
||||
pl = obj.PropertiesList
|
||||
if not "Height" in pl:
|
||||
obj.addProperty("App::PropertyLength","Height","Floor",QT_TRANSLATE_NOOP("App::Property","The height of this object"))
|
||||
@@ -142,10 +143,6 @@ class _Floor:
|
||||
if not hasattr(obj,"Placement"):
|
||||
# obj can be a Part Feature and already has a placement
|
||||
obj.addProperty("App::PropertyPlacement","Placement","Base",QT_TRANSLATE_NOOP("App::Property","The placement of this object"))
|
||||
if not "IfcType" in pl:
|
||||
obj.addProperty("App::PropertyEnumeration","IfcType","IFC",QT_TRANSLATE_NOOP("App::Property","The type of this object"))
|
||||
import ArchIFC
|
||||
obj.IfcType = ArchIFC.IfcTypes
|
||||
self.Type = "Floor"
|
||||
|
||||
def onDocumentRestored(self,obj):
|
||||
@@ -161,6 +158,7 @@ class _Floor:
|
||||
return None
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
ArchIFC.IfcProduct.onChanged(self, obj, prop)
|
||||
|
||||
if not hasattr(self,"Object"):
|
||||
# on restore, self.Object is not there anymore
|
||||
|
||||
@@ -9,181 +9,185 @@ else:
|
||||
return txt
|
||||
|
||||
import ArchIFCSchema
|
||||
IfcTypes = ['Undefined']+[''.join(map(lambda x: x if x.islower() else " "+x, t[3:]))[1:] for t in ArchIFCSchema.IfcProducts.keys()]
|
||||
|
||||
def setProperties(obj):
|
||||
IfcTypes = [''.join(map(lambda x: x if x.islower() else " "+x, t[3:]))[1:] for t in ArchIFCSchema.IfcProducts.keys()]
|
||||
|
||||
"Checks and sets all the needed IFC-related properties"
|
||||
class IfcRoot:
|
||||
def setProperties(self, obj):
|
||||
if not "IfcData" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyMap","IfcData","IFC",QT_TRANSLATE_NOOP("App::Property","IFC data"))
|
||||
|
||||
if not "IfcType" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyEnumeration","IfcType","IFC",QT_TRANSLATE_NOOP("App::Property","The type of this object"))
|
||||
obj.IfcType = IfcTypes
|
||||
if not "IfcType" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyEnumeration","IfcType","IFC",QT_TRANSLATE_NOOP("App::Property","The type of this object"))
|
||||
obj.IfcType = self.getCanonicalisedIfcTypes()
|
||||
|
||||
if not "IfcData" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyMap","IfcData","IFC",QT_TRANSLATE_NOOP("App::Property","IFC data"))
|
||||
if not "IfcProperties" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyMap","IfcProperties","IFC",QT_TRANSLATE_NOOP("App::Property","IFC properties of this object"))
|
||||
|
||||
if not "IfcProperties" in obj.PropertiesList:
|
||||
obj.addProperty("App::PropertyMap","IfcProperties","IFC",QT_TRANSLATE_NOOP("App::Property","IFC properties of this object"))
|
||||
self.migrateDeprecatedAttributes(obj)
|
||||
|
||||
migrateDeprecatedAttributes(obj)
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "IfcType":
|
||||
self.setupIfcAttributes(obj)
|
||||
self.setupIfcComplexAttributes(obj)
|
||||
if obj.getGroupOfProperty(prop) == "IFC Attributes":
|
||||
self.setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop))
|
||||
|
||||
def onChanged(obj, prop):
|
||||
def setupIfcAttributes(self, obj):
|
||||
ifcTypeSchema = self.getIfcTypeSchema(obj.IfcType)
|
||||
if ifcTypeSchema is None:
|
||||
return
|
||||
self.purgeUnusedIfcAttributesFromPropertiesList(ifcTypeSchema, obj)
|
||||
self.addIfcAttributes(ifcTypeSchema, obj)
|
||||
|
||||
"Called by Arch object's OnChanged method"
|
||||
def setupIfcComplexAttributes(self, obj):
|
||||
ifcTypeSchema = self.getIfcTypeSchema(obj.IfcType)
|
||||
if ifcTypeSchema is None:
|
||||
return
|
||||
IfcData = obj.IfcData
|
||||
if "complex_attributes" not in IfcData:
|
||||
IfcData["complex_attributes"] = "{}"
|
||||
ifcComplexAttributes = json.loads(IfcData["complex_attributes"])
|
||||
for attribute in ifcTypeSchema["complex_attributes"]:
|
||||
if attribute["name"] not in ifcComplexAttributes.keys():
|
||||
ifcComplexAttributes[attribute["name"]] = {}
|
||||
IfcData["complex_attributes"] = json.dumps(ifcComplexAttributes)
|
||||
obj.IfcData = IfcData
|
||||
|
||||
if prop == "IfcType":
|
||||
setupIfcAttributes(obj)
|
||||
if obj.getGroupOfProperty(prop) == "IFC Attributes":
|
||||
setObjIfcAttributeValue(obj, prop, obj.getPropertyByName(prop))
|
||||
def getIfcTypeSchema(self, IfcType):
|
||||
name = "Ifc" + IfcType.replace(" ", "")
|
||||
if IfcType == "Undefined":
|
||||
name = "IfcBuildingElementProxy"
|
||||
if name in self.getIfcSchema():
|
||||
return self.getIfcSchema()[name]
|
||||
return None
|
||||
|
||||
def getIfcProduct(IfcType):
|
||||
|
||||
"Returns an IFC product name from an obj.IfcType"
|
||||
|
||||
name = "Ifc" + IfcType.replace(" ", "")
|
||||
if IfcType == "Undefined":
|
||||
name = "IfcBuildingElementProxy"
|
||||
if name in ArchIFCSchema.IfcProducts:
|
||||
return ArchIFCSchema.IfcProducts[name]
|
||||
return None
|
||||
def getIfcSchema(self):
|
||||
return {}
|
||||
|
||||
def getIfcProductAttribute(ifcProduct, name):
|
||||
|
||||
"Returns the attributes of a given product"
|
||||
def getCanonicalisedIfcTypes(self):
|
||||
schema = self.getIfcSchema()
|
||||
return [''.join(map(lambda x: x if x.islower() else " "+x, t[3:]))[1:] for t in schema.keys()]
|
||||
|
||||
for attribute in ifcProduct["attributes"]:
|
||||
if attribute["name"].replace(' ', '') == name:
|
||||
return attribute
|
||||
return None
|
||||
def getIfcAttributeSchema(self, ifcTypeSchema, name):
|
||||
for attribute in ifcTypeSchema["attributes"]:
|
||||
if attribute["name"].replace(' ', '') == name:
|
||||
return attribute
|
||||
return None
|
||||
|
||||
def setupIfcAttributes(obj):
|
||||
def addIfcAttributes(self, ifcTypeSchema, obj):
|
||||
for attribute in ifcTypeSchema["attributes"]:
|
||||
if attribute["name"] in obj.PropertiesList \
|
||||
or attribute["name"] == "RefLatitude" \
|
||||
or attribute["name"] == "RefLongitude" \
|
||||
or attribute["name"] == "Name":
|
||||
continue
|
||||
self.addIfcAttribute(obj, attribute)
|
||||
self.addIfcAttributeValueExpressions(obj, attribute)
|
||||
|
||||
"Sets the necessary IFC attribute properties for an object"
|
||||
|
||||
ifcProduct = getIfcProduct(obj.IfcType)
|
||||
if ifcProduct is None:
|
||||
return
|
||||
purgeUnusedIfcAttributesFromPropertiesList(ifcProduct, obj)
|
||||
addIfcProductAttributesToObj(ifcProduct, obj)
|
||||
|
||||
def addIfcProductAttributesToObj(ifcProduct, obj):
|
||||
|
||||
"Adds the necessary attribute properties to an object"
|
||||
|
||||
for attribute in ifcProduct["attributes"]:
|
||||
if attribute["name"] in obj.PropertiesList \
|
||||
or attribute["name"] == "RefLatitude" \
|
||||
or attribute["name"] == "RefLongitude":
|
||||
continue
|
||||
addIfcProductAttribute(obj, attribute)
|
||||
addIfcAttributeValueExpressions(obj, attribute)
|
||||
|
||||
def addIfcProductAttribute(obj, attribute):
|
||||
|
||||
"Adds a given attribute property"
|
||||
|
||||
if not hasattr(obj,"IfcData"):
|
||||
return
|
||||
IfcData = obj.IfcData
|
||||
if "attributes" not in IfcData:
|
||||
IfcData["attributes"] = "{}"
|
||||
IfcAttributes = json.loads(IfcData["attributes"])
|
||||
IfcAttributes[attribute["name"]] = attribute
|
||||
IfcData["attributes"] = json.dumps(IfcAttributes)
|
||||
obj.IfcData = IfcData
|
||||
if attribute["is_enum"]:
|
||||
obj.addProperty("App::PropertyEnumeration", attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
|
||||
setattr(obj, attribute["name"], attribute["enum_values"])
|
||||
else:
|
||||
import ArchIFCSchema
|
||||
propertyType = "App::" + ArchIFCSchema.IfcTypes[attribute["type"]]["property"]
|
||||
obj.addProperty(propertyType, attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
|
||||
|
||||
def addIfcAttributeValueExpressions(obj, attribute):
|
||||
|
||||
"Binds the given attribute properties with expressions"
|
||||
|
||||
if not attribute["name"] in obj.PropertiesList:
|
||||
return
|
||||
if obj.getGroupOfProperty(attribute["name"]) != "IFC Attributes":
|
||||
return
|
||||
if attribute["name"] == "OverallWidth":
|
||||
if "Length" in obj.PropertiesList:
|
||||
obj.setExpression("OverallWidth", "Length.Value")
|
||||
elif "Width" in obj.PropertiesList:
|
||||
obj.setExpression("OverallWidth", "Width.Value")
|
||||
elif obj.Shape and (obj.Shape.BoundBox.XLength > obj.Shape.BoundBox.YLength):
|
||||
obj.setExpression("OverallWidth", "Shape.BoundBox.XLength")
|
||||
elif obj.Shape:
|
||||
obj.setExpression("OverallWidth", "Shape.BoundBox.YLength")
|
||||
elif attribute["name"] == "OverallHeight":
|
||||
if "Height" in obj.PropertiesList:
|
||||
obj.setExpression("OverallHeight", "Height.Value")
|
||||
def addIfcAttribute(self, obj, attribute):
|
||||
if not hasattr(obj, "IfcData"):
|
||||
return
|
||||
IfcData = obj.IfcData
|
||||
if "attributes" not in IfcData:
|
||||
IfcData["attributes"] = "{}"
|
||||
IfcAttributes = json.loads(IfcData["attributes"])
|
||||
IfcAttributes[attribute["name"]] = attribute
|
||||
IfcData["attributes"] = json.dumps(IfcAttributes)
|
||||
obj.IfcData = IfcData
|
||||
if attribute["is_enum"]:
|
||||
obj.addProperty("App::PropertyEnumeration", attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
|
||||
setattr(obj, attribute["name"], attribute["enum_values"])
|
||||
else:
|
||||
obj.setExpression("OverallHeight", "Shape.BoundBox.ZLength")
|
||||
elif attribute["name"] == "ElevationWithFlooring":
|
||||
if "Shape" in obj.PropertiesList:
|
||||
import ArchIFCSchema
|
||||
propertyType = "App::" + ArchIFCSchema.IfcTypes[attribute["type"]]["property"]
|
||||
obj.addProperty(propertyType, attribute["name"], "IFC Attributes", QT_TRANSLATE_NOOP("App::Property", "Description of IFC attributes are not yet implemented"))
|
||||
|
||||
def addIfcAttributeValueExpressions(self, obj, attribute):
|
||||
if obj.getGroupOfProperty(attribute["name"]) != "IFC Attributes" \
|
||||
or attribute["name"] not in obj.PropertiesList:
|
||||
return
|
||||
if attribute["name"] == "OverallWidth":
|
||||
if "Length" in obj.PropertiesList:
|
||||
obj.setExpression("OverallWidth", "Length.Value")
|
||||
elif "Width" in obj.PropertiesList:
|
||||
obj.setExpression("OverallWidth", "Width.Value")
|
||||
elif obj.Shape and (obj.Shape.BoundBox.XLength > obj.Shape.BoundBox.YLength):
|
||||
obj.setExpression("OverallWidth", "Shape.BoundBox.XLength")
|
||||
elif obj.Shape:
|
||||
obj.setExpression("OverallWidth", "Shape.BoundBox.YLength")
|
||||
elif attribute["name"] == "OverallHeight":
|
||||
if "Height" in obj.PropertiesList:
|
||||
obj.setExpression("OverallHeight", "Height.Value")
|
||||
else:
|
||||
obj.setExpression("OverallHeight", "Shape.BoundBox.ZLength")
|
||||
elif attribute["name"] == "ElevationWithFlooring" and "Shape" in obj.PropertiesList:
|
||||
obj.setExpression("ElevationWithFlooring", "Shape.BoundBox.ZMin")
|
||||
elif attribute["name"] == "Elevation":
|
||||
if "Placement" in obj.PropertiesList:
|
||||
elif attribute["name"] == "Elevation" and "Placement" in obj.PropertiesList:
|
||||
obj.setExpression("Elevation", "Placement.Base.z")
|
||||
elif attribute["name"] == "NominalDiameter":
|
||||
if "Diameter" in obj.PropertiesList:
|
||||
elif attribute["name"] == "NominalDiameter" and "Diameter" in obj.PropertiesList:
|
||||
obj.setExpression("NominalDiameter", "Diameter.Value")
|
||||
elif attribute["name"] == "BarLength":
|
||||
if "Length" in obj.PropertiesList:
|
||||
elif attribute["name"] == "BarLength" and "Length" in obj.PropertiesList:
|
||||
obj.setExpression("BarLength", "Length.Value")
|
||||
elif attribute["name"] == "RefElevation":
|
||||
if "Elevation" in obj.PropertiesList:
|
||||
elif attribute["name"] == "RefElevation" and "Elevation" in obj.PropertiesList:
|
||||
obj.setExpression("RefElevation", "Elevation.Value")
|
||||
elif attribute["name"] == "LongName":
|
||||
obj.LongName = obj.Label
|
||||
elif attribute["name"] == "LongName":
|
||||
obj.LongName = obj.Label
|
||||
|
||||
def setObjIfcAttributeValue(obj, attributeName, value):
|
||||
|
||||
"Sets the value of a given attribute property"
|
||||
|
||||
IfcData = obj.IfcData
|
||||
if "attributes" not in IfcData:
|
||||
IfcData["attributes"] = "{}"
|
||||
IfcAttributes = json.loads(IfcData["attributes"])
|
||||
if isinstance(value, FreeCAD.Units.Quantity):
|
||||
value = float(value)
|
||||
if not attributeName in IfcAttributes:
|
||||
IfcAttributes[attributeName] = {}
|
||||
IfcAttributes[attributeName]["value"] = value
|
||||
IfcData["attributes"] = json.dumps(IfcAttributes)
|
||||
obj.IfcData = IfcData
|
||||
def setObjIfcAttributeValue(self, obj, attributeName, value):
|
||||
IfcData = obj.IfcData
|
||||
if "attributes" not in IfcData:
|
||||
IfcData["attributes"] = "{}"
|
||||
IfcAttributes = json.loads(IfcData["attributes"])
|
||||
if isinstance(value, FreeCAD.Units.Quantity):
|
||||
value = float(value)
|
||||
if not attributeName in IfcAttributes:
|
||||
IfcAttributes[attributeName] = {}
|
||||
IfcAttributes[attributeName]["value"] = value
|
||||
IfcData["attributes"] = json.dumps(IfcAttributes)
|
||||
obj.IfcData = IfcData
|
||||
|
||||
def purgeUnusedIfcAttributesFromPropertiesList(ifcProduct, obj):
|
||||
|
||||
"Removes unused attribute properties"
|
||||
|
||||
for property in obj.PropertiesList:
|
||||
if obj.getGroupOfProperty(property) != "IFC Attributes":
|
||||
continue
|
||||
ifcProductAttribute = getIfcProductAttribute(ifcProduct, property)
|
||||
if ifcProductAttribute is None or ifcProductAttribute["is_enum"] is True:
|
||||
obj.removeProperty(property)
|
||||
def setObjIfcComplexAttributeValue(self, obj, attributeName, value):
|
||||
IfcData = obj.IfcData
|
||||
IfcAttributes = json.loads(IfcData["complex_attributes"])
|
||||
IfcAttributes[attributeName] = value
|
||||
IfcData["complex_attributes"] = json.dumps(IfcAttributes)
|
||||
obj.IfcData = IfcData
|
||||
|
||||
def migrateDeprecatedAttributes(obj):
|
||||
|
||||
"Fixes obsolete properties"
|
||||
def getObjIfcComplexAttribute(self, obj, attributeName):
|
||||
return json.loads(obj.IfcData["complex_attributes"])[attributeName]
|
||||
|
||||
if "Role" in obj.PropertiesList:
|
||||
r = obj.Role
|
||||
obj.removeProperty("Role")
|
||||
if r in IfcTypes:
|
||||
obj.IfcType = r
|
||||
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" Role property to IfcType\n")
|
||||
def purgeUnusedIfcAttributesFromPropertiesList(self, ifcTypeSchema, obj):
|
||||
for property in obj.PropertiesList:
|
||||
if obj.getGroupOfProperty(property) != "IFC Attributes":
|
||||
continue
|
||||
ifcAttribute = self.getIfcAttributeSchema(ifcTypeSchema, property)
|
||||
if ifcAttribute is None or ifcAttribute["is_enum"] is True:
|
||||
obj.removeProperty(property)
|
||||
|
||||
if "IfcRole" in obj.PropertiesList:
|
||||
r = obj.IfcRole
|
||||
obj.removeProperty("IfcRole")
|
||||
if r in IfcTypes:
|
||||
obj.IfcType = r
|
||||
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" IfcRole property to IfcType\n")
|
||||
|
||||
if "IfcAttributes"in obj.PropertiesList:
|
||||
obj.IfcData = obj.IfcAttributes
|
||||
obj.removeProperty("IfcAttributes")
|
||||
def migrateDeprecatedAttributes(self, obj):
|
||||
if "Role" in obj.PropertiesList:
|
||||
r = obj.Role
|
||||
obj.removeProperty("Role")
|
||||
if r in IfcTypes:
|
||||
obj.IfcType = r
|
||||
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" Role property to IfcType\n")
|
||||
|
||||
if "IfcRole" in obj.PropertiesList:
|
||||
r = obj.IfcRole
|
||||
obj.removeProperty("IfcRole")
|
||||
if r in IfcTypes:
|
||||
obj.IfcType = r
|
||||
FreeCAD.Console.PrintMessage("Upgrading "+obj.Label+" IfcRole property to IfcType\n")
|
||||
|
||||
if "IfcAttributes"in obj.PropertiesList:
|
||||
obj.IfcData = obj.IfcAttributes
|
||||
obj.removeProperty("IfcAttributes")
|
||||
|
||||
class IfcProduct(IfcRoot):
|
||||
def getIfcSchema(self):
|
||||
return ArchIFCSchema.IfcProducts
|
||||
|
||||
class IfcContext(IfcRoot):
|
||||
def getIfcSchema(self):
|
||||
return ArchIFCSchema.IfcContexts
|
||||
|
||||
@@ -3,6 +3,10 @@ import FreeCAD, os, json
|
||||
ifcVersions = ["IFC4", "IFC2X3"]
|
||||
IfcVersion = ifcVersions[FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("IfcVersion",0)]
|
||||
|
||||
with open(os.path.join(FreeCAD.getResourceDir(), "Mod", "Arch", "Presets",
|
||||
"ifc_contexts_" + IfcVersion + ".json")) as f:
|
||||
IfcContexts = json.load(f)
|
||||
|
||||
with open(os.path.join(FreeCAD.getResourceDir(), "Mod", "Arch", "Presets",
|
||||
"ifc_products_" + IfcVersion + ".json")) as f:
|
||||
IfcProducts = json.load(f)
|
||||
|
||||
71
src/Mod/Arch/ArchIFCView.py
Normal file
71
src/Mod/Arch/ArchIFCView.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import FreeCAD, ArchIFC
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtGui
|
||||
|
||||
class IfcContextView:
|
||||
def setEdit(self, viewObject, mode):
|
||||
# What does mode do?
|
||||
FreeCADGui.Control.showDialog(IfcContextUI(viewObject.Object))
|
||||
return True
|
||||
|
||||
class IfcContextUI:
|
||||
def __init__(self, object):
|
||||
self.object = object
|
||||
self.lineEditObjects = []
|
||||
self.createBaseLayout()
|
||||
self.createMapConversionFormLayout()
|
||||
self.prefillMapConversionForm()
|
||||
self.form = self.baseWidget
|
||||
|
||||
def accept(self):
|
||||
data = {}
|
||||
for lineEdit in self.lineEditObjects:
|
||||
data[lineEdit.objectName()] = lineEdit.text()
|
||||
ArchIFC.IfcRoot.setObjIfcComplexAttributeValue(self, self.object, "RepresentationContexts", data)
|
||||
return True
|
||||
|
||||
def createBaseLayout(self):
|
||||
self.baseWidget = QtGui.QWidget()
|
||||
self.baseLayout = QtGui.QVBoxLayout(self.baseWidget)
|
||||
|
||||
def createMapConversionFormLayout(self):
|
||||
self.baseLayout.addWidget(self.createLabel("Target Coordinate Reference System"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("name", "Name"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("description", "Description"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("geodetic_datum", "Geodetic datum"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("vertical_datum", "Vertical datum"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("map_projection", "Map projection"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("map_zone", "Map zone"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("map_unit", "Map unit"))
|
||||
|
||||
self.baseLayout.addWidget(self.createLabel("Map Conversion"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("eastings", "Eastings"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("northings", "Northings"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("orthogonal_height", "Orthogonal height"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("true_north", "True north (anti-clockwise from +Y)"))
|
||||
self.baseLayout.addLayout(self.createFormEntry("scale", "Scale"))
|
||||
|
||||
def prefillMapConversionForm(self):
|
||||
data = ArchIFC.IfcRoot.getObjIfcComplexAttribute(self, self.object, "RepresentationContexts")
|
||||
for lineEdit in self.lineEditObjects:
|
||||
if lineEdit.objectName() in data.keys():
|
||||
lineEdit.setText(data[lineEdit.objectName()])
|
||||
|
||||
def createFormEntry(self, name, label):
|
||||
layout = QtGui.QHBoxLayout(self.baseWidget)
|
||||
layout.addWidget(self.createLabel(label))
|
||||
layout.addWidget(self.createLineEdit(name))
|
||||
return layout
|
||||
|
||||
def createLabel(self, value):
|
||||
label = QtGui.QLabel(self.baseWidget)
|
||||
label.setText(QtGui.QApplication.translate("Arch", value, None))
|
||||
return label
|
||||
|
||||
def createLineEdit(self, name):
|
||||
lineEdit = QtGui.QLineEdit(self.baseWidget)
|
||||
lineEdit.setObjectName(name)
|
||||
self.lineEditObjects.append(lineEdit)
|
||||
return lineEdit
|
||||
126
src/Mod/Arch/ArchProject.py
Normal file
126
src/Mod/Arch/ArchProject.py
Normal file
@@ -0,0 +1,126 @@
|
||||
# -*- coding: utf8 -*-
|
||||
|
||||
#***************************************************************************
|
||||
#* *
|
||||
#* Copyright (c) 2011 *
|
||||
#* Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* This program is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with this program; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
|
||||
import FreeCAD,Draft,ArchComponent,ArchCommands,math,re,datetime,ArchIFC,ArchIFCView
|
||||
if FreeCAD.GuiUp:
|
||||
import FreeCADGui
|
||||
from PySide import QtCore, QtGui
|
||||
from DraftTools import translate
|
||||
from PySide.QtCore import QT_TRANSLATE_NOOP
|
||||
else:
|
||||
def translate(ctxt,txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
return txt
|
||||
|
||||
## @package ArchProject
|
||||
# \ingroup ARCH
|
||||
# \brief The Project object and tools
|
||||
#
|
||||
# This module provides tools to build Project objects.
|
||||
|
||||
__title__="FreeCAD Project"
|
||||
__author__ = "Yorik van Havre"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
def makeProject(sites=None, name="Project"):
|
||||
|
||||
'''makeProject(sites): creates a project aggregating the list of sites.'''
|
||||
|
||||
if not FreeCAD.ActiveDocument:
|
||||
return FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
|
||||
import Part
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Project")
|
||||
obj.Label = translate("Arch", name)
|
||||
_Project(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
_ViewProviderProject(obj.ViewObject)
|
||||
if sites:
|
||||
obj.Group = sites
|
||||
return obj
|
||||
|
||||
class _CommandProject:
|
||||
|
||||
"the Arch Project command definition"
|
||||
|
||||
def GetResources(self):
|
||||
return {'Pixmap' : 'Arch_Project',
|
||||
'MenuText': QT_TRANSLATE_NOOP("Arch_Project", "Project"),
|
||||
'Accel': "P, O",
|
||||
'ToolTip': QT_TRANSLATE_NOOP("Arch_Project", "Creates a project entity aggregating the selected sites.")}
|
||||
|
||||
def IsActive(self):
|
||||
return not FreeCAD.ActiveDocument is None
|
||||
|
||||
def Activated(self):
|
||||
selection = FreeCADGui.Selection.getSelection()
|
||||
siteobj = []
|
||||
|
||||
for obj in selection:
|
||||
if hasattr(obj, "IfcType") and obj.IfcType == "Site":
|
||||
siteobj.append(obj)
|
||||
|
||||
ss = "[ "
|
||||
for o in siteobj:
|
||||
ss += "FreeCAD.ActiveDocument." + o.Name + ", "
|
||||
ss += "]"
|
||||
FreeCAD.ActiveDocument.openTransaction(translate("Arch","Create Project"))
|
||||
FreeCADGui.addModule("Arch")
|
||||
FreeCADGui.doCommand("obj = Arch.makeProject("+ss+")")
|
||||
FreeCADGui.addModule("Draft")
|
||||
FreeCADGui.doCommand("Draft.autogroup(obj)")
|
||||
FreeCAD.ActiveDocument.commitTransaction()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
class _Project(ArchIFC.IfcContext):
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
self.setProperties(obj)
|
||||
obj.IfcType = "Project"
|
||||
|
||||
def setProperties(self, obj):
|
||||
ArchIFC.IfcContext.setProperties(self, obj)
|
||||
pl = obj.PropertiesList
|
||||
if not hasattr(obj,"Group"):
|
||||
obj.addExtension("App::GroupExtensionPython", self)
|
||||
self.Type = "Project"
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
self.setProperties(obj)
|
||||
|
||||
class _ViewProviderProject(ArchIFCView.IfcContextView):
|
||||
|
||||
def __init__(self,vobj):
|
||||
vobj.Proxy = self
|
||||
vobj.addExtension("Gui::ViewProviderGroupExtensionPython", self)
|
||||
|
||||
def getIcon(self):
|
||||
import Arch_rc
|
||||
return ":/icons/Arch_Project_Tree.svg"
|
||||
|
||||
if FreeCAD.GuiUp:
|
||||
FreeCADGui.addCommand('Arch_Project', _CommandProject())
|
||||
@@ -521,7 +521,7 @@ Site creation aborted.") + "\n"
|
||||
|
||||
|
||||
|
||||
class _Site:
|
||||
class _Site(ArchIFC.IfcProduct):
|
||||
|
||||
"The Site object"
|
||||
|
||||
@@ -533,8 +533,7 @@ class _Site:
|
||||
|
||||
def setProperties(self,obj):
|
||||
|
||||
import ArchIFC
|
||||
ArchIFC.setProperties(obj)
|
||||
ArchIFC.IfcProduct.setProperties(self, obj)
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "Terrain" in pl:
|
||||
@@ -638,7 +637,7 @@ class _Site:
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
|
||||
ArchIFC.onChanged(obj, prop)
|
||||
ArchIFC.IfcProduct.onChanged(self, obj, prop)
|
||||
if prop == "Terrain":
|
||||
if obj.Terrain:
|
||||
if FreeCAD.GuiUp:
|
||||
|
||||
@@ -118,7 +118,7 @@ def makeStructure(baseobj=None,length=None,width=None,height=None,name="Structur
|
||||
obj.Length = h
|
||||
|
||||
if not height and not length:
|
||||
obj.IfcType = "Undefined"
|
||||
obj.IfcType = "Building Element Proxy"
|
||||
elif obj.Length > obj.Height:
|
||||
obj.IfcType = "Beam"
|
||||
obj.Label = translate("Arch","Beam")
|
||||
|
||||
@@ -521,13 +521,13 @@ class _Wall(ArchComponent.Component):
|
||||
|
||||
"The Wall object"
|
||||
|
||||
def __init__(self,obj):
|
||||
def __init__(self, obj):
|
||||
|
||||
ArchComponent.Component.__init__(self,obj)
|
||||
ArchComponent.Component.__init__(self, obj)
|
||||
self.setProperties(obj)
|
||||
obj.IfcType = "Wall"
|
||||
|
||||
def setProperties(self,obj):
|
||||
def setProperties(self, obj):
|
||||
|
||||
lp = obj.PropertiesList
|
||||
if not "Length" in lp:
|
||||
@@ -750,12 +750,10 @@ class _Wall(ArchComponent.Component):
|
||||
obj.Area = obj.Length.Value * obj.Height.Value
|
||||
|
||||
def onBeforeChange(self,obj,prop):
|
||||
|
||||
if prop == "Length":
|
||||
self.oldLength = obj.Length.Value
|
||||
|
||||
def onChanged(self,obj,prop):
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
if prop == "Length":
|
||||
if obj.Base and obj.Length.Value and hasattr(self,"oldLength") and (self.oldLength != None) and (self.oldLength != obj.Length.Value):
|
||||
if obj.Base.isDerivedFrom("Part::Feature"):
|
||||
|
||||
@@ -7,10 +7,14 @@ SET(Arch_SRCS
|
||||
InitGui.py
|
||||
ArchComponent.py
|
||||
ArchIFC.py
|
||||
ArchIFCView.py
|
||||
ArchIFCSchema.py
|
||||
ArchProject.py
|
||||
ArchWall.py
|
||||
importIFC.py
|
||||
importIFClegacy.py
|
||||
importIFCHelper.py
|
||||
exportIFCHelper.py
|
||||
Arch.py
|
||||
ArchBuilding.py
|
||||
ArchFloor.py
|
||||
@@ -62,6 +66,7 @@ SET(Arch_presets
|
||||
Presets/ifc_products_IFC4.json
|
||||
Presets/ifc_types_IFC2X3.json
|
||||
Presets/ifc_types_IFC4.json
|
||||
Presets/ifc_contexts_IFC4.json
|
||||
)
|
||||
|
||||
SOURCE_GROUP("" FILES ${Arch_SRCS})
|
||||
|
||||
@@ -34,7 +34,7 @@ class ArchWorkbench(Workbench):
|
||||
|
||||
# arch tools
|
||||
self.archtools = ["Arch_Wall","Arch_Structure","Arch_Rebar","Arch_BuildingPart",
|
||||
"Arch_Floor","Arch_Building","Arch_Site","Arch_Reference",
|
||||
"Arch_Project", "Arch_Site", "Arch_Building", "Arch_Floor", "Arch_Reference",
|
||||
"Arch_Window","Arch_Roof","Arch_AxisTools",
|
||||
"Arch_SectionPlane","Arch_Space","Arch_Stairs",
|
||||
"Arch_PanelTools","Arch_Equipment",
|
||||
|
||||
146
src/Mod/Arch/Presets/ifc_contexts_IFC4.json
Normal file
146
src/Mod/Arch/Presets/ifc_contexts_IFC4.json
Normal file
@@ -0,0 +1,146 @@
|
||||
{
|
||||
"IfcProject": {
|
||||
"is_abstract": false,
|
||||
"parent": "IfcContext",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "GlobalId",
|
||||
"type": "IfcGloballyUniqueId",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Description",
|
||||
"type": "IfcText",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "ObjectType",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "LongName",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Phase",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
}
|
||||
],
|
||||
"complex_attributes": [
|
||||
{
|
||||
"name": "OwnerHistory",
|
||||
"type": "IfcOwnerHistory"
|
||||
},
|
||||
{
|
||||
"name": "IsNestedBy",
|
||||
"type": "IfcRelNests"
|
||||
},
|
||||
{
|
||||
"name": "IsDecomposedBy",
|
||||
"type": "IfcRelAggregates"
|
||||
},
|
||||
{
|
||||
"name": "RepresentationContexts",
|
||||
"type": "IfcRepresentationContext"
|
||||
},
|
||||
{
|
||||
"name": "UnitsInContext",
|
||||
"type": "IfcUnitAssignment"
|
||||
},
|
||||
{
|
||||
"name": "IsDefinedBy",
|
||||
"type": "IfcRelDefinesByProperties"
|
||||
},
|
||||
{
|
||||
"name": "Declares",
|
||||
"type": "IfcRelDeclares"
|
||||
}
|
||||
]
|
||||
},
|
||||
"IfcProjectLibrary": {
|
||||
"is_abstract": false,
|
||||
"parent": "IfcContext",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "GlobalId",
|
||||
"type": "IfcGloballyUniqueId",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Description",
|
||||
"type": "IfcText",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "ObjectType",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "LongName",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Phase",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
}
|
||||
],
|
||||
"complex_attributes": [
|
||||
{
|
||||
"name": "OwnerHistory",
|
||||
"type": "IfcOwnerHistory"
|
||||
},
|
||||
{
|
||||
"name": "IsNestedBy",
|
||||
"type": "IfcRelNests"
|
||||
},
|
||||
{
|
||||
"name": "IsDecomposedBy",
|
||||
"type": "IfcRelAggregates"
|
||||
},
|
||||
{
|
||||
"name": "RepresentationContexts",
|
||||
"type": "IfcRepresentationContext"
|
||||
},
|
||||
{
|
||||
"name": "UnitsInContext",
|
||||
"type": "IfcUnitAssignment"
|
||||
},
|
||||
{
|
||||
"name": "IsDefinedBy",
|
||||
"type": "IfcRelDefinesByProperties"
|
||||
},
|
||||
{
|
||||
"name": "Declares",
|
||||
"type": "IfcRelDeclares"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@
|
||||
<file>icons/Arch_Cell.svg</file>
|
||||
<file>icons/Arch_Wall.svg</file>
|
||||
<file>icons/Arch_Site.svg</file>
|
||||
<file>icons/Arch_Project.svg</file>
|
||||
<file>icons/Arch_Structure.svg</file>
|
||||
<file>icons/Arch_Add.svg</file>
|
||||
<file>icons/Arch_Remove.svg</file>
|
||||
@@ -21,6 +22,7 @@
|
||||
<file>icons/Arch_Floor_Tree.svg</file>
|
||||
<file>icons/Arch_SectionPlane_Tree.svg</file>
|
||||
<file>icons/Arch_Site_Tree.svg</file>
|
||||
<file>icons/Arch_Project_Tree.svg</file>
|
||||
<file>icons/Arch_Structure_Tree.svg</file>
|
||||
<file>icons/Arch_Structure_Clone.svg</file>
|
||||
<file>icons/Arch_Window_Tree.svg</file>
|
||||
|
||||
423
src/Mod/Arch/Resources/icons/Arch_Project.svg
Normal file
423
src/Mod/Arch/Resources/icons/Arch_Project.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
435
src/Mod/Arch/Resources/icons/Arch_Project_Tree.svg
Normal file
435
src/Mod/Arch/Resources/icons/Arch_Project_Tree.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
@@ -43,6 +43,7 @@ from DraftGeomUtils import vec
|
||||
from importIFC import recycler
|
||||
from importIFC import dd2dms
|
||||
from importIFC import decode
|
||||
import exportIFCHelper
|
||||
|
||||
|
||||
## @package exportIFC
|
||||
@@ -94,7 +95,6 @@ DATA;
|
||||
#8=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#9=IFCAXIS2PLACEMENT3D(#8,#7,#6);
|
||||
#10=IFCDIRECTION((0.,1.,0.));
|
||||
#11=IFCGEOMETRICREPRESENTATIONCONTEXT('Plan','Model',3,1.E-05,#9,#10);
|
||||
#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
|
||||
#13=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
|
||||
#14=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
|
||||
@@ -103,7 +103,6 @@ DATA;
|
||||
#17=IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.017453292519943295),#16);
|
||||
#18=IFCCONVERSIONBASEDUNIT(#12,.PLANEANGLEUNIT.,'DEGREE',#17);
|
||||
#19=IFCUNITASSIGNMENT((#13,#14,#15,#18));
|
||||
#20=IFCPROJECT('$projectid',#5,'$project',$,$,$,$,(#11),#19);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
"""
|
||||
@@ -196,8 +195,6 @@ def export(exportList,filename,colors=None):
|
||||
template = template.replace("$company",FreeCAD.ActiveDocument.Company)
|
||||
template = template.replace("$email",email)
|
||||
template = template.replace("$now",str(int(time.time())))
|
||||
template = template.replace("$projectid",FreeCAD.ActiveDocument.Uid[:22].replace("-","_"))
|
||||
template = template.replace("$project",FreeCAD.ActiveDocument.Name)
|
||||
template = template.replace("$filename",os.path.basename(filename))
|
||||
template = template.replace("$timestamp",str(time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime())))
|
||||
if hasattr(ifcopenshell,"version"):
|
||||
@@ -212,12 +209,7 @@ def export(exportList,filename,colors=None):
|
||||
global ifcfile, surfstyles, clones, sharedobjects, profiledefs, shapedefs
|
||||
ifcfile = ifcopenshell.open(templatefile)
|
||||
history = ifcfile.by_type("IfcOwnerHistory")[0]
|
||||
context = ifcfile.by_type("IfcGeometricRepresentationContext")[0]
|
||||
project = ifcfile.by_type("IfcProject")[0]
|
||||
objectslist = Draft.getGroupContents(exportList,walls=True,addgroups=True)
|
||||
if(Draft.getObjectsOfType(objectslist, "Site")): # we assume one site and one representation context only
|
||||
trueNorthX = math.tan(-Draft.getObjectsOfType(objectslist, "Site")[0].Declination.getValueAs(FreeCAD.Units.Radian))
|
||||
context.TrueNorth.DirectionRatios = (trueNorthX, 1., 1.)
|
||||
annotations = []
|
||||
for obj in objectslist:
|
||||
if obj.isDerivedFrom("Part::Part2DObject"):
|
||||
@@ -234,6 +226,16 @@ def export(exportList,filename,colors=None):
|
||||
objectslist = [obj for obj in objectslist if Draft.getType(obj) not in ["Dimension","Material","MaterialContainer","WorkingPlaneProxy"]]
|
||||
if FULL_PARAMETRIC:
|
||||
objectslist = Arch.getAllChildren(objectslist)
|
||||
|
||||
contextCreator = exportIFCHelper.ContextCreator(ifcfile, objectslist)
|
||||
context = contextCreator.model_view_subcontext
|
||||
project = contextCreator.project
|
||||
objectslist = [obj for obj in objectslist if obj != contextCreator.project_object]
|
||||
|
||||
if Draft.getObjectsOfType(objectslist, "Site"): # we assume one site and one representation context only
|
||||
trueNorthX = math.tan(-Draft.getObjectsOfType(objectslist, "Site")[0].Declination.getValueAs(FreeCAD.Units.Radian))
|
||||
contextCreator.model_context.TrueNorth.DirectionRatios = (trueNorthX, 1., 1.)
|
||||
|
||||
products = {} # { Name: IfcEntity, ... }
|
||||
subproducts = {} # { Name: IfcEntity, ... } for storing additions/subtractions and other types of subcomponents of a product
|
||||
surfstyles = {} # { (r,g,b): IfcEntity, ... }
|
||||
@@ -262,6 +264,7 @@ def export(exportList,filename,colors=None):
|
||||
#print(objectslist)
|
||||
|
||||
# testing if more than one site selected (forbidden in IFC)
|
||||
# TODO: Moult: This is not forbidden in IFC.
|
||||
|
||||
if len(Draft.getObjectsOfType(objectslist,"Site")) > 1:
|
||||
FreeCAD.Console.PrintError("More than one site is selected, which is forbidden by IFC standards. Please export only one site by IFC file.\n")
|
||||
@@ -593,7 +596,7 @@ def export(exportList,filename,colors=None):
|
||||
#if DEBUG : print(" adding ifc attributes")
|
||||
props = []
|
||||
for key in obj.IfcData:
|
||||
if not (key in ["attributes","IfcUID","FlagForceBrep"]):
|
||||
if not (key in ["attributes", "complex_attributes", "IfcUID", "FlagForceBrep"]):
|
||||
|
||||
# (deprecated) properties in IfcData dict are stored as "key":"type(value)"
|
||||
|
||||
@@ -872,7 +875,7 @@ def export(exportList,filename,colors=None):
|
||||
|
||||
# sites
|
||||
|
||||
for site in Draft.getObjectsOfType(objectslist,"Site"):
|
||||
for site in exportIFCHelper.getObjectsOfIfcType(objectslist, "Site"):
|
||||
objs = Draft.getGroupContents(site,walls=True,addgroups=True)
|
||||
objs = Arch.pruneIncluded(objs)
|
||||
children = []
|
||||
|
||||
140
src/Mod/Arch/exportIFCHelper.py
Normal file
140
src/Mod/Arch/exportIFCHelper.py
Normal file
@@ -0,0 +1,140 @@
|
||||
import FreeCAD, Draft, json, ifcopenshell, math
|
||||
|
||||
def getObjectsOfIfcType(objects, ifcType):
|
||||
results = []
|
||||
for object in objects:
|
||||
if object.IfcType == ifcType:
|
||||
results.append(object)
|
||||
return results
|
||||
|
||||
class SIUnitCreator:
|
||||
def __init__(self, file, text, type):
|
||||
self.prefixes = ["EXA", "PETA", "TERA", "GIGA", "MEGA", "KILO", "HECTO",
|
||||
"DECA", "DECI", "CENTI", "MILLI", "MICRO", "NANO", "PICO", "FEMTO",
|
||||
"ATTO"]
|
||||
self.unitNames = ["AMPERE", "BECQUEREL", "CANDELA", "COULOMB",
|
||||
"CUBIC_METRE", "DEGREE CELSIUS", "FARAD", "GRAM", "GRAY", "HENRY",
|
||||
"HERTZ", "JOULE", "KELVIN", "LUMEN", "LUX", "MOLE", "NEWTON", "OHM",
|
||||
"PASCAL", "RADIAN", "SECOND", "SIEMENS", "SIEVERT", "SQUARE METRE",
|
||||
"METRE", "STERADIAN", "TESLA", "VOLT", "WATT", "WEBER"]
|
||||
self.text = text
|
||||
self.SIUnit = file.createIfcSIUnit(None, type, self.getSIPrefix(), self.getSIUnitName())
|
||||
|
||||
def getSIPrefix(self):
|
||||
for prefix in self.prefixes:
|
||||
if prefix in self.text.upper():
|
||||
return prefix
|
||||
return None
|
||||
|
||||
def getSIUnitName(self):
|
||||
for unitName in self.unitNames:
|
||||
if unitName in self.text.upper():
|
||||
return unitName
|
||||
return None
|
||||
|
||||
class ContextCreator:
|
||||
def __init__(self, file, objects):
|
||||
self.file = file
|
||||
self.objects = objects
|
||||
self.project_object = self.getProjectObject()
|
||||
self.project_data = self.getProjectObjectData()
|
||||
self.model_context = self.createGeometricRepresentationContext()
|
||||
self.model_view_subcontext = self.createGeometricRepresentationSubContext()
|
||||
self.target_crs = self.createTargetCRS()
|
||||
self.map_conversion = self.createMapConversion()
|
||||
self.project = self.createProject()
|
||||
|
||||
def createGeometricRepresentationContext(self):
|
||||
return self.file.createIfcGeometricRepresentationContext(
|
||||
None, "Model",
|
||||
3, 1.0E-05,
|
||||
self.file.by_type("IfcAxis2Placement3D")[0],
|
||||
self.createTrueNorth())
|
||||
|
||||
def createGeometricRepresentationSubContext(self):
|
||||
return self.file.createIfcGeometricRepresentationSubContext(
|
||||
"Body", "Model",
|
||||
None, None, None, None,
|
||||
self.model_context, None, "MODEL_VIEW", None)
|
||||
|
||||
def createTargetCRS(self):
|
||||
try:
|
||||
SIUnit = SIUnitCreator(self.file, self.project_data["map_unit"], "LENGTHUNIT")
|
||||
return self.file.createIfcProjectedCRS(
|
||||
self.project_data["name"],
|
||||
self.project_data["description"],
|
||||
self.project_data["geodetic_datum"],
|
||||
self.project_data["vertical_datum"],
|
||||
self.project_data["map_projection"],
|
||||
self.project_data["map_zone"],
|
||||
SIUnit.SIUnit
|
||||
)
|
||||
except:
|
||||
return None
|
||||
|
||||
def createMapConversion(self):
|
||||
try:
|
||||
return self.file.createIfcMapConversion(
|
||||
self.model_context, self.target_crs,
|
||||
float(self.project_data["eastings"]),
|
||||
float(self.project_data["northings"]),
|
||||
float(self.project_data["orthogonal_height"]),
|
||||
self.calculateXAxisAbscissa(),
|
||||
self.calculateXAxisOrdinate(),
|
||||
float(self.project_data["scale"])
|
||||
)
|
||||
except:
|
||||
return None
|
||||
|
||||
def createTrueNorth(self):
|
||||
return self.file.createIfcDirection(
|
||||
(self.calculateXAxisAbscissa(), self.calculateXAxisOrdinate(), 0.))
|
||||
|
||||
def calculateXAxisAbscissa(self):
|
||||
if "true_north" in self.project_data:
|
||||
return math.cos(math.radians(float(self.project_data["true_north"]) + 90))
|
||||
return 0.
|
||||
|
||||
def calculateXAxisOrdinate(self):
|
||||
if "true_north" in self.project_data:
|
||||
return math.sin(math.radians(float(self.project_data["true_north"]) + 90))
|
||||
return 1.
|
||||
|
||||
def createProject(self):
|
||||
if not self.project_object:
|
||||
return self.createAutomaticProject()
|
||||
return self.createCustomProject()
|
||||
|
||||
def createAutomaticProject(self):
|
||||
return self.file.createIfcProject(
|
||||
self.getProjectGUID(),
|
||||
self.file.by_type("IfcOwnerHistory")[0],
|
||||
FreeCAD.ActiveDocument.Name, None,
|
||||
None, None, None, [self.model_context],
|
||||
self.file.by_type("IfcUnitAssignment")[0])
|
||||
|
||||
def createCustomProject(self):
|
||||
return self.file.createIfcProject(
|
||||
self.getProjectGUID(),
|
||||
self.file.by_type("IfcOwnerHistory")[0],
|
||||
self.project_object.Label, self.project_object.Description,
|
||||
self.project_object.ObjectType, self.project_object.LongName,
|
||||
self.project_object.Phase,
|
||||
[self.model_context],
|
||||
self.file.by_type("IfcUnitAssignment")[0])
|
||||
|
||||
def getProjectGUID(self):
|
||||
# TODO: Do not generate a new one each time, but at least this one
|
||||
# conforms to the community consensus on how a GUID is generated.
|
||||
return ifcopenshell.guid.new()
|
||||
|
||||
def getProjectObject(self):
|
||||
try:
|
||||
return getObjectsOfIfcType(self.objects, "Project")[0]
|
||||
except:
|
||||
return None
|
||||
|
||||
def getProjectObjectData(self):
|
||||
if not self.project_object:
|
||||
return {}
|
||||
return json.loads(self.project_object.IfcData['complex_attributes'])["RepresentationContexts"]
|
||||
@@ -38,6 +38,7 @@ import Draft
|
||||
import Arch
|
||||
import DraftVecUtils
|
||||
import ArchIFCSchema
|
||||
import importIFCHelper
|
||||
|
||||
## @package importIFC
|
||||
# \ingroup ARCH
|
||||
@@ -403,6 +404,9 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
import FreeCADGui
|
||||
FreeCADGui.ActiveDocument.activeView().viewAxonometric()
|
||||
|
||||
projectImporter = importIFCHelper.ProjectImporter(ifcfile, objects)
|
||||
projectImporter.execute()
|
||||
|
||||
# handle IFC products
|
||||
|
||||
for product in products:
|
||||
@@ -623,53 +627,55 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
# full Arch objects
|
||||
|
||||
for freecadtype,ifctypes in typesmap.items():
|
||||
if ptype in ifctypes:
|
||||
if clone:
|
||||
obj = getattr(Arch,"make"+freecadtype)(name=name)
|
||||
obj.CloneOf = clone
|
||||
if shape:
|
||||
if shape.Solids:
|
||||
s1 = shape.Solids[0]
|
||||
else:
|
||||
s1 = shape
|
||||
if clone.Shape.Solids:
|
||||
s2 = clone.Shape.Solids[0]
|
||||
else:
|
||||
s1 = clone.Shape
|
||||
if hasattr(s1,"CenterOfMass") and hasattr(s2,"CenterOfMass"):
|
||||
v = s1.CenterOfMass.sub(s2.CenterOfMass)
|
||||
if product.Representation:
|
||||
r = getRotation(product.Representation.Representations[0].Items[0].MappingTarget)
|
||||
if not r.isNull():
|
||||
v = v.add(s2.CenterOfMass)
|
||||
v = v.add(r.multVec(s2.CenterOfMass.negative()))
|
||||
obj.Placement.Rotation = r
|
||||
obj.Placement.move(v)
|
||||
else:
|
||||
print("failed to compute placement ",)
|
||||
else:
|
||||
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
|
||||
if freecadtype in ["Wall","Structure"] and baseobj and baseobj.isDerivedFrom("Part::Extrusion"):
|
||||
# remove intermediary extrusion for types that can extrude themselves
|
||||
obj.Base = baseobj.Base
|
||||
obj.Placement = obj.Placement.multiply(baseobj.Placement)
|
||||
obj.Height = baseobj.Dir.Length
|
||||
obj.Normal = FreeCAD.Vector(baseobj.Dir).normalize()
|
||||
bn = baseobj.Name
|
||||
FreeCAD.ActiveDocument.removeObject(bn)
|
||||
if (freecadtype in ["Structure","Wall"]) and not baseobj:
|
||||
# remove sizes to prevent auto shape creation for types that don't require a base object
|
||||
obj.Height = 0
|
||||
obj.Width = 0
|
||||
obj.Length = 0
|
||||
if store:
|
||||
sharedobjects[store] = obj
|
||||
|
||||
if ptype == "IfcBuildingStorey":
|
||||
if product.Elevation:
|
||||
obj.Placement.Base.z = product.Elevation * getScaling(ifcfile)
|
||||
if ptype not in ifctypes:
|
||||
continue
|
||||
if clone:
|
||||
obj = getattr(Arch,"make"+freecadtype)(name=name)
|
||||
obj.CloneOf = clone
|
||||
if shape:
|
||||
if shape.Solids:
|
||||
s1 = shape.Solids[0]
|
||||
else:
|
||||
s1 = shape
|
||||
if clone.Shape.Solids:
|
||||
s2 = clone.Shape.Solids[0]
|
||||
else:
|
||||
s1 = clone.Shape
|
||||
if hasattr(s1,"CenterOfMass") and hasattr(s2,"CenterOfMass"):
|
||||
v = s1.CenterOfMass.sub(s2.CenterOfMass)
|
||||
if product.Representation:
|
||||
r = getRotation(product.Representation.Representations[0].Items[0].MappingTarget)
|
||||
if not r.isNull():
|
||||
v = v.add(s2.CenterOfMass)
|
||||
v = v.add(r.multVec(s2.CenterOfMass.negative()))
|
||||
obj.Placement.Rotation = r
|
||||
obj.Placement.move(v)
|
||||
else:
|
||||
print("failed to compute placement ",)
|
||||
else:
|
||||
obj = getattr(Arch,"make"+freecadtype)(baseobj=baseobj,name=name)
|
||||
if freecadtype in ["Wall","Structure"] and baseobj and baseobj.isDerivedFrom("Part::Extrusion"):
|
||||
# remove intermediary extrusion for types that can extrude themselves
|
||||
obj.Base = baseobj.Base
|
||||
obj.Placement = obj.Placement.multiply(baseobj.Placement)
|
||||
obj.Height = baseobj.Dir.Length
|
||||
obj.Normal = FreeCAD.Vector(baseobj.Dir).normalize()
|
||||
bn = baseobj.Name
|
||||
FreeCAD.ActiveDocument.removeObject(bn)
|
||||
if (freecadtype in ["Structure","Wall"]) and not baseobj:
|
||||
# remove sizes to prevent auto shape creation for types that don't require a base object
|
||||
obj.Height = 0
|
||||
obj.Width = 0
|
||||
obj.Length = 0
|
||||
if store:
|
||||
sharedobjects[store] = obj
|
||||
|
||||
break
|
||||
if ptype == "IfcBuildingStorey":
|
||||
if product.Elevation:
|
||||
obj.Placement.Base.z = product.Elevation * getScaling(ifcfile)
|
||||
|
||||
break
|
||||
|
||||
if not obj:
|
||||
obj = Arch.makeComponent(baseobj,name=name)
|
||||
@@ -704,6 +710,8 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
# setting IFC attributes
|
||||
|
||||
for attribute in ArchIFCSchema.IfcProducts[product.is_a()]["attributes"]:
|
||||
if attribute["name"] == "Name":
|
||||
continue
|
||||
#print("attribute:",attribute["name"])
|
||||
if hasattr(product, attribute["name"]) and getattr(product, attribute["name"]) and hasattr(obj,attribute["name"]):
|
||||
#print("Setting attribute",attribute["name"],"to",getattr(product, attribute["name"]))
|
||||
@@ -1025,23 +1033,25 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
# additions
|
||||
|
||||
for host,children in additions.items():
|
||||
if host in objects.keys():
|
||||
cobs = []
|
||||
for child in children:
|
||||
if child in objects.keys():
|
||||
if child not in swallowed: # don't add objects already in groups
|
||||
cobs.append(objects[child])
|
||||
if cobs:
|
||||
if DEBUG and first:
|
||||
print("")
|
||||
first = False
|
||||
if DEBUG and (len(cobs) > 10) and (not(Draft.getType(objects[host]) in ["Site","Building","Floor","BuildingPart"])):
|
||||
# avoid huge fusions
|
||||
print("more than 10 shapes to add: skipping.")
|
||||
else:
|
||||
if DEBUG: print(" adding",len(cobs), "object(s) to", objects[host].Label)
|
||||
Arch.addComponents(cobs,objects[host])
|
||||
if DEBUG: FreeCAD.ActiveDocument.recompute()
|
||||
if host not in objects.keys():
|
||||
continue
|
||||
cobs = []
|
||||
for child in children:
|
||||
if child in objects.keys() \
|
||||
and child not in swallowed: # don't add objects already in groups
|
||||
cobs.append(objects[child])
|
||||
if not cobs:
|
||||
continue
|
||||
if DEBUG and first:
|
||||
print("")
|
||||
first = False
|
||||
if DEBUG and (len(cobs) > 10) and (not(Draft.getType(objects[host]) in ["Site","Building","Floor","BuildingPart","Project"])):
|
||||
# avoid huge fusions
|
||||
print("more than 10 shapes to add: skipping.")
|
||||
else:
|
||||
if DEBUG: print(" adding",len(cobs), "object(s) to", objects[host].Label)
|
||||
Arch.addComponents(cobs,objects[host])
|
||||
if DEBUG: FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
if DEBUG and first: print("done.")
|
||||
|
||||
@@ -1051,7 +1061,7 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
|
||||
for obj in objects.values():
|
||||
if obj.isDerivedFrom("Part::Feature"):
|
||||
if obj.Shape.isNull() and not(Draft.getType(obj) in ["Site"]):
|
||||
if obj.Shape.isNull() and not(Draft.getType(obj) in ["Site","Project"]):
|
||||
Arch.rebuildArchShape(obj)
|
||||
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
@@ -1673,7 +1683,7 @@ class recycler:
|
||||
else:
|
||||
if isinstance(pvalue,float) and pvalue < 0.000000001: # remove the exp notation that some bim apps hate
|
||||
pvalue = 0
|
||||
c = self.ifcfile.createIfcPropertySingleValue(name,None,ifcfile.create_entity(ptype,pvalue),None)
|
||||
c = self.ifcfile.createIfcPropertySingleValue(name,None,self.ifcfile.create_entity(ptype,pvalue),None)
|
||||
if self.compress:
|
||||
self.propertysinglevalues[key] = c
|
||||
return c
|
||||
|
||||
70
src/Mod/Arch/importIFCHelper.py
Normal file
70
src/Mod/Arch/importIFCHelper.py
Normal file
@@ -0,0 +1,70 @@
|
||||
import Arch, ArchIFC, math
|
||||
|
||||
class ProjectImporter:
|
||||
def __init__(self, file, objects):
|
||||
self.file = file
|
||||
self.objects = objects
|
||||
|
||||
def execute(self):
|
||||
self.project = self.file.by_type("IfcProject")[0]
|
||||
self.object = Arch.makeProject()
|
||||
self.objects[self.project.id()] = self.object
|
||||
self.setAttributes()
|
||||
self.setComplexAttributes()
|
||||
|
||||
def setAttributes(self):
|
||||
for property in self.object.PropertiesList:
|
||||
if hasattr(self.project, property) and getattr(self.project, property):
|
||||
setattr(self.object, property, getattr(self.project, property))
|
||||
|
||||
def setComplexAttributes(self):
|
||||
try:
|
||||
mapConversion = self.project.RepresentationContexts[0].HasCoordinateOperation[0]
|
||||
|
||||
data = self.extractTargetCRSData(mapConversion.TargetCRS)
|
||||
data.update(self.extractMapConversionData(mapConversion))
|
||||
ArchIFC.IfcRoot.setObjIfcComplexAttributeValue(self, self.object, "RepresentationContexts", data)
|
||||
except:
|
||||
# This scenario occurs validly in IFC2X3, as the mapConversion does
|
||||
# not exist
|
||||
return
|
||||
|
||||
def extractTargetCRSData(self, targetCRS):
|
||||
mappings = {
|
||||
"name": "Name",
|
||||
"description": "Description",
|
||||
"geodetic_datum": "GeodeticDatum",
|
||||
"vertical_datum": "VerticalDatum",
|
||||
"map_projection": "MapProjection",
|
||||
"map_zone": "MapZone"
|
||||
}
|
||||
data = {}
|
||||
for attributeName, ifcName in mappings.items():
|
||||
data[attributeName] = str(getattr(targetCRS, ifcName))
|
||||
|
||||
if targetCRS.MapUnit.Prefix:
|
||||
data["map_unit"] = targetCRS.MapUnit.Prefix.title() + targetCRS.MapUnit.Name.lower()
|
||||
else:
|
||||
data["map_unit"] = targetCRS.MapUnit.Name.title()
|
||||
|
||||
return data
|
||||
|
||||
def extractMapConversionData(self, mapConversion):
|
||||
mappings = {
|
||||
"eastings": "Eastings",
|
||||
"northings": "Northings",
|
||||
"orthogonal_height": "OrthogonalHeight",
|
||||
"x_axis_abscissa": "XAxisAbscissa",
|
||||
"x_axis_ordinate": "XAxisOrdinate",
|
||||
"scale": "Scale"
|
||||
}
|
||||
data = {}
|
||||
for attributeName, ifcName in mappings.items():
|
||||
data[attributeName] = str(getattr(mapConversion, ifcName))
|
||||
|
||||
data["true_north"] = str(self.calculateTrueNorthAngle(
|
||||
mapConversion.XAxisAbscissa, mapConversion.XAxisOrdinate))
|
||||
return data
|
||||
|
||||
def calculateTrueNorthAngle(self, x, y):
|
||||
return round(math.degrees(math.atan2(y, x)) - 90, 6)
|
||||
Reference in New Issue
Block a user