Arch: Merge of PR #2259 - Fix ifc project

This commit is contained in:
Yorik van Havre
2019-08-14 16:04:52 -03:00
parent a12b851ab3
commit 09d0b2d0e7
23 changed files with 11337 additions and 964 deletions

View File

@@ -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 *

View File

@@ -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:

View File

@@ -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):

View File

@@ -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"):

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View 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
View 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())

View File

@@ -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:

View File

@@ -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")

View File

@@ -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"):

View File

@@ -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})

View File

@@ -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",

View 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

View File

@@ -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>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -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 = []

View 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"]

View File

@@ -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

View 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)