Arch: Added IFC export to the GUI + using new ifcopenshell for import - fixes #1005
This commit is contained in:
parent
a2cba17d3f
commit
7ceef577a2
|
@ -146,6 +146,7 @@ FreeCADGui.addWorkbench(ArchWorkbench)
|
||||||
|
|
||||||
# add import/export types
|
# add import/export types
|
||||||
FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC")
|
FreeCAD.addImportType("Industry Foundation Classes (*.ifc)","importIFC")
|
||||||
|
FreeCAD.addExportType("Industry Foundation Classes (*.ifc)","importIFC")
|
||||||
FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ")
|
FreeCAD.addExportType("Wavefront OBJ - Arch module (*.obj)","importOBJ")
|
||||||
FreeCAD.addExportType("WebGL file (*.html)","importWebGL")
|
FreeCAD.addExportType("WebGL file (*.html)","importWebGL")
|
||||||
FreeCAD.addImportType("Collada (*.dae)","importDAE")
|
FreeCAD.addImportType("Collada (*.dae)","importDAE")
|
||||||
|
|
|
@ -30,15 +30,18 @@
|
||||||
|
|
||||||
import sys, uuid, time, math
|
import sys, uuid, time, math
|
||||||
|
|
||||||
|
# if you already have another version of IfcOpenShell:
|
||||||
# adding here the path to the ifcwrap folder of the ifcopenshell build. That
|
# adding here the path to the ifcwrap folder of the ifcopenshell build. That
|
||||||
# folder must also contain an __init__.py file. This is to differentiate with
|
# folder must also contain an __init__.py file. This is to differentiate with
|
||||||
# systemwide-installed IfcOpenShell, which has the same name.
|
# systemwide-installed IfcOpenShell, which has the same name.
|
||||||
|
# if you have such setup, uncomment the following 2 lines and comment out the
|
||||||
sys.path.append("/home/yorik/Sources/build/ifcopenshell-dev")
|
# third one.
|
||||||
from ifcwrap import IfcImport as IfcExport
|
#sys.path.append("/home/yorik/Sources/build/ifcopenshell-dev")
|
||||||
|
#from ifcwrap import IfcImport
|
||||||
|
import IfcImport
|
||||||
|
|
||||||
# checking that we got the right importer, with export capabilities
|
# checking that we got the right importer, with export capabilities
|
||||||
if not hasattr(IfcExport,"IfcFile"):
|
if not hasattr(IfcImport,"IfcFile"):
|
||||||
print "Wrong version of IfcOpenShell"
|
print "Wrong version of IfcOpenShell"
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
@ -57,7 +60,7 @@ holder = _tempEntityHolder()
|
||||||
|
|
||||||
def new():
|
def new():
|
||||||
"""new(): returns a new empty ifc file holder"""
|
"""new(): returns a new empty ifc file holder"""
|
||||||
fil = IfcExport.IfcFile()
|
fil = IfcImport.IfcFile()
|
||||||
return fil
|
return fil
|
||||||
|
|
||||||
def uid():
|
def uid():
|
||||||
|
@ -110,7 +113,7 @@ def create(ifcdoc=None,ifcname=None,arguments=[]):
|
||||||
"""create(ifcdoc,ifcname,[arguments]):creates an entity
|
"""create(ifcdoc,ifcname,[arguments]):creates an entity
|
||||||
of the given name in the given document and optionally
|
of the given name in the given document and optionally
|
||||||
gives it an ordered list of arguments"""
|
gives it an ordered list of arguments"""
|
||||||
entity = IfcExport.Entity(ifcname)
|
entity = IfcImport.Entity(ifcname)
|
||||||
if ifcdoc:
|
if ifcdoc:
|
||||||
ifcdoc.add(entity)
|
ifcdoc.add(entity)
|
||||||
# this is a temporary hack while ifcopenshell has no ref counting
|
# this is a temporary hack while ifcopenshell has no ref counting
|
||||||
|
@ -121,7 +124,7 @@ def create(ifcdoc=None,ifcname=None,arguments=[]):
|
||||||
arg = arguments[i]
|
arg = arguments[i]
|
||||||
if isinstance(arg,tuple):
|
if isinstance(arg,tuple):
|
||||||
if len(arg) == 3:
|
if len(arg) == 3:
|
||||||
arg = IfcExport.Doubles(arg)
|
arg = IfcImport.Doubles(arg)
|
||||||
entity.set_argument(i,arg)
|
entity.set_argument(i,arg)
|
||||||
return entity
|
return entity
|
||||||
|
|
||||||
|
@ -280,7 +283,7 @@ class IfcDocument(object):
|
||||||
Creates an empty IFC document."""
|
Creates an empty IFC document."""
|
||||||
|
|
||||||
def __init__(self,filepath="",name="",owner="",organization="",application="Python IFC exporter",version="0.0"):
|
def __init__(self,filepath="",name="",owner="",organization="",application="Python IFC exporter",version="0.0"):
|
||||||
self._fileobject = IfcExport.IfcFile()
|
self._fileobject = IfcImport.IfcFile()
|
||||||
self._person = create(self._fileobject,"IfcPerson",[None,None,"",None,None,None,None,None])
|
self._person = create(self._fileobject,"IfcPerson",[None,None,"",None,None,None,None,None])
|
||||||
self._org = create(self._fileobject,"IfcOrganization",[None,"",None,None,None])
|
self._org = create(self._fileobject,"IfcOrganization",[None,"",None,None,None])
|
||||||
pno = create(self._fileobject,"IfcPersonAndOrganization",[self._person,self._org,None])
|
pno = create(self._fileobject,"IfcPersonAndOrganization",[self._person,self._org,None])
|
||||||
|
|
|
@ -32,6 +32,7 @@ __url__ = "http://www.freecadweb.org"
|
||||||
subtractiveTypes = ["IfcOpeningElement"] # elements that must be subtracted from their parents
|
subtractiveTypes = ["IfcOpeningElement"] # elements that must be subtracted from their parents
|
||||||
SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.exp"
|
SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.exp"
|
||||||
MAKETEMPFILES = False # if True, shapes are passed from ifcopenshell to freecad through temp files
|
MAKETEMPFILES = False # if True, shapes are passed from ifcopenshell to freecad through temp files
|
||||||
|
ADDPLACEMENT = False # if True, placements get computed (only for newer ifcopenshell)
|
||||||
# end config
|
# end config
|
||||||
|
|
||||||
if open.__module__ == '__builtin__':
|
if open.__module__ == '__builtin__':
|
||||||
|
@ -98,108 +99,176 @@ def read(filename):
|
||||||
|
|
||||||
# parsing the IFC file
|
# parsing the IFC file
|
||||||
t1 = time.time()
|
t1 = time.time()
|
||||||
num_lines = sum(1 for line in pyopen(filename))
|
|
||||||
|
|
||||||
processedIds = []
|
processedIds = []
|
||||||
|
|
||||||
if getIfcOpenShell() and not FORCE_PYTHON_PARSER:
|
if getIfcOpenShell() and not FORCE_PYTHON_PARSER:
|
||||||
# use the IfcOpenShell parser
|
# use the IfcOpenShell parser
|
||||||
|
|
||||||
|
# check for IFcOpenShellVersion
|
||||||
|
global IOC_ADVANCED
|
||||||
|
if hasattr(IfcImport,"IfcFile"):
|
||||||
|
IOC_ADVANCED = True
|
||||||
|
else:
|
||||||
|
IOC_ADVANCED = False
|
||||||
|
|
||||||
# preparing IfcOpenShell
|
# preparing IfcOpenShell
|
||||||
if DEBUG: global ifcObjects,ifcParents
|
if DEBUG: global ifcObjects,ifcParents
|
||||||
ifcObjects = {} # a table to relate ifc id with freecad object
|
ifcObjects = {} # a table to relate ifc id with freecad object
|
||||||
ifcParents = {} # a table to relate ifc id with parent id
|
ifcParents = {} # a table to relate ifc id with parent id
|
||||||
if hasattr(IfcImport,"DISABLE_OPENING_SUBTRACTIONS") and SEPARATE_OPENINGS:
|
if SEPARATE_OPENINGS:
|
||||||
IfcImport.Settings(IfcImport.DISABLE_OPENING_SUBTRACTIONS,True)
|
if hasattr(IfcImport,"DISABLE_OPENING_SUBTRACTIONS"):
|
||||||
|
IfcImport.Settings(IfcImport.DISABLE_OPENING_SUBTRACTIONS,True)
|
||||||
else:
|
else:
|
||||||
SKIP.append("IfcOpeningElement")
|
SKIP.append("IfcOpeningElement")
|
||||||
useShapes = False
|
useShapes = False
|
||||||
if hasattr(IfcImport,"USE_BREP_DATA"):
|
if IOC_ADVANCED:
|
||||||
|
useShapes = True
|
||||||
|
elif hasattr(IfcImport,"USE_BREP_DATA"):
|
||||||
IfcImport.Settings(IfcImport.USE_BREP_DATA,True)
|
IfcImport.Settings(IfcImport.USE_BREP_DATA,True)
|
||||||
useShapes = True
|
useShapes = True
|
||||||
else:
|
else:
|
||||||
if DEBUG: print "Warning: IfcOpenShell version very old, unable to handle Brep data"
|
if DEBUG: print "Warning: IfcOpenShell version very old, unable to handle Brep data"
|
||||||
|
|
||||||
# processing geometry
|
# opening file
|
||||||
if IfcImport.Init(filename):
|
if IOC_ADVANCED:
|
||||||
while True:
|
global ifc
|
||||||
|
ifc = IfcImport.open(filename)
|
||||||
obj = IfcImport.Get()
|
objects = ifc.by_type("IfcProduct")
|
||||||
if DEBUG: print "["+str(int((float(obj.id)/num_lines)*100))+"%] parsing ",obj.id,": ",obj.name," of type ",obj.type
|
num_lines = len(objects)
|
||||||
|
relations = ifc.by_type("IfcRelAggregates") + ifc.by_type("IfcRelContainedInSpatialStructure") + ifc.by_type("IfcRelVoidsElement")
|
||||||
# retrieving name
|
if not objects:
|
||||||
n = getName(obj)
|
print "Error opening IFC file"
|
||||||
|
return
|
||||||
# skip types
|
else:
|
||||||
if obj.type in SKIP:
|
num_lines = sum(1 for line in pyopen(filename))
|
||||||
if DEBUG: print "skipping because type is in skip list"
|
if not IfcImport.Init(filename):
|
||||||
nobj = None
|
print "Error opening IFC file"
|
||||||
|
return
|
||||||
|
|
||||||
# check if object was already processed, to workaround an ifcopenshell bug
|
# processing geometry
|
||||||
elif obj.id in processedIds:
|
idx = 0
|
||||||
if DEBUG: print "skipping because this object was already processed"
|
while True:
|
||||||
|
if IOC_ADVANCED:
|
||||||
|
obj = objects[idx]
|
||||||
|
idx += 1
|
||||||
|
objid = int(str(obj).split("=")[0].strip("#"))
|
||||||
|
objname = obj.get_argument(obj.get_argument_index("Name"))
|
||||||
|
objtype = str(obj).split("=")[1].split("(")[0]
|
||||||
|
objparentid = -1
|
||||||
|
for r in relations:
|
||||||
|
if r.is_a("IfcRelAggregates"):
|
||||||
|
for c in getAttr(r,"RelatedObjects"):
|
||||||
|
if str(obj) == str(c):
|
||||||
|
objparentid = int(str(getAttr(r,"RelatingObject")).split("=")[0].strip("#"))
|
||||||
|
elif r.is_a("IfcRelContainedInSpatialStructure"):
|
||||||
|
for c in getAttr(r,"RelatedElements"):
|
||||||
|
if str(obj) == str(c):
|
||||||
|
objparentid = int(str(getAttr(r,"RelatingStructure")).split("=")[0].strip("#"))
|
||||||
|
elif r.is_a("IfcRelVoidsElement"):
|
||||||
|
if str(obj) == str(getAttr(r,"RelatedOpeningElement")):
|
||||||
|
objparentid = int(str(getAttr(r,"RelatingBuildingElement")).split("=")[0].strip("#"))
|
||||||
|
|
||||||
|
else:
|
||||||
|
obj = IfcImport.Get()
|
||||||
|
objid = obj.id
|
||||||
|
idx = objid
|
||||||
|
objname = obj.name
|
||||||
|
objtype = obj.type
|
||||||
|
objparentid = obj.parent_id
|
||||||
|
if DEBUG: print "["+str(int((float(idx)/num_lines)*100))+"%] parsing ",objid,": ",objname," of type ",objtype
|
||||||
|
|
||||||
|
# retrieving name
|
||||||
|
n = getCleanName(objname,objid,objtype)
|
||||||
|
|
||||||
|
# skip types
|
||||||
|
if objtype in SKIP:
|
||||||
|
if DEBUG: print "skipping because type is in skip list"
|
||||||
|
nobj = None
|
||||||
|
|
||||||
|
# check if object was already processed, to workaround an ifcopenshell bug
|
||||||
|
elif objid in processedIds:
|
||||||
|
if DEBUG: print "skipping because this object was already processed"
|
||||||
|
|
||||||
|
else:
|
||||||
|
# build shape
|
||||||
|
shape = None
|
||||||
|
if useShapes:
|
||||||
|
shape = getShape(obj,objid)
|
||||||
|
|
||||||
|
# walls
|
||||||
|
if objtype in ["IfcWallStandardCase","IfcWall"]:
|
||||||
|
nobj = makeWall(objid,shape,n)
|
||||||
|
|
||||||
|
# windows
|
||||||
|
elif objtype in ["IfcWindow","IfcDoor"]:
|
||||||
|
nobj = makeWindow(objid,shape,n)
|
||||||
|
|
||||||
|
# structs
|
||||||
|
elif objtype in ["IfcBeam","IfcColumn","IfcSlab","IfcFooting"]:
|
||||||
|
nobj = makeStructure(objid,shape,objtype,n)
|
||||||
|
|
||||||
|
# roofs
|
||||||
|
elif objtype in ["IfcRoof"]:
|
||||||
|
nobj = makeRoof(objid,shape,n)
|
||||||
|
|
||||||
|
# furniture
|
||||||
|
elif objtype in ["IfcFurnishingElement"]:
|
||||||
|
nobj = FreeCAD.ActiveDocument.addObject("Part::Feature",n)
|
||||||
|
nobj.Shape = shape
|
||||||
|
|
||||||
|
# sites
|
||||||
|
elif objtype in ["IfcSite"]:
|
||||||
|
nobj = makeSite(objid,shape,n)
|
||||||
|
|
||||||
|
# floors
|
||||||
|
elif objtype in ["IfcBuildingStorey"]:
|
||||||
|
nobj = Arch.makeFloor(name=n)
|
||||||
|
nobj.Label = n
|
||||||
|
|
||||||
|
# floors
|
||||||
|
elif objtype in ["IfcBuilding"]:
|
||||||
|
nobj = Arch.makeBuilding(name=n)
|
||||||
|
nobj.Label = n
|
||||||
|
|
||||||
|
# spaces
|
||||||
|
elif objtype in ["IfcSpace"]:
|
||||||
|
nobj = makeSpace(objid,shape,n)
|
||||||
|
|
||||||
|
elif shape:
|
||||||
|
# treat as dumb parts
|
||||||
|
#if DEBUG: print "Fixme: Shape-containing object not handled: ",obj.id, " ", obj.type
|
||||||
|
nobj = FreeCAD.ActiveDocument.addObject("Part::Feature",n)
|
||||||
|
nobj.Label = n
|
||||||
|
nobj.Shape = shape
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# build shape
|
# treat as meshes
|
||||||
shape = None
|
if DEBUG: print "Warning: Object without shape: ",objid, " ", objtype
|
||||||
if useShapes:
|
me,pl = getMesh(obj)
|
||||||
shape = getShape(obj)
|
nobj = FreeCAD.ActiveDocument.addObject("Mesh::Feature",n)
|
||||||
|
nobj.Label = n
|
||||||
# walls
|
nobj.Mesh = me
|
||||||
if obj.type in ["IfcWallStandardCase","IfcWall"]:
|
nobj.Placement = pl
|
||||||
nobj = makeWall(obj.id,shape,n)
|
|
||||||
|
# registering object number and parent
|
||||||
# windows
|
if objparentid > 0:
|
||||||
elif obj.type in ["IfcWindow","IfcDoor"]:
|
ifcParents[objid] = [objparentid,not (objtype in subtractiveTypes)]
|
||||||
nobj = makeWindow(obj.id,shape,n)
|
ifcObjects[objid] = nobj
|
||||||
|
processedIds.append(objid)
|
||||||
# structs
|
|
||||||
elif obj.type in ["IfcBeam","IfcColumn","IfcSlab","IfcFooting"]:
|
if IOC_ADVANCED:
|
||||||
nobj = makeStructure(obj.id,shape,obj.type,n)
|
if idx >= len(objects):
|
||||||
|
break
|
||||||
# roofs
|
else:
|
||||||
elif obj.type in ["IfcRoof"]:
|
|
||||||
nobj = makeRoof(obj.id,shape,n)
|
|
||||||
|
|
||||||
# furniture
|
|
||||||
elif obj.type in ["IfcFurnishingElement"]:
|
|
||||||
nobj = FreeCAD.ActiveDocument.addObject("Part::Feature",n)
|
|
||||||
nobj.Shape = shape
|
|
||||||
|
|
||||||
# sites
|
|
||||||
elif obj.type in ["IfcSite"]:
|
|
||||||
nobj = makeSite(obj.id,shape,n)
|
|
||||||
|
|
||||||
# spaces
|
|
||||||
elif obj.type in ["IfcSpace"]:
|
|
||||||
nobj = makeSpace(obj.id,shape,n)
|
|
||||||
|
|
||||||
elif shape:
|
|
||||||
# treat as dumb parts
|
|
||||||
#if DEBUG: print "Fixme: Shape-containing object not handled: ",obj.id, " ", obj.type
|
|
||||||
nobj = FreeCAD.ActiveDocument.addObject("Part::Feature",n)
|
|
||||||
nobj.Shape = shape
|
|
||||||
|
|
||||||
else:
|
|
||||||
# treat as meshes
|
|
||||||
if DEBUG: print "Warning: Object without shape: ",obj.id, " ", obj.type
|
|
||||||
me,pl = getMesh(obj)
|
|
||||||
nobj = FreeCAD.ActiveDocument.addObject("Mesh::Feature",n)
|
|
||||||
nobj.Mesh = me
|
|
||||||
nobj.Placement = pl
|
|
||||||
|
|
||||||
# registering object number and parent
|
|
||||||
if obj.parent_id > 0:
|
|
||||||
ifcParents[obj.id] = [obj.parent_id,not (obj.type in subtractiveTypes)]
|
|
||||||
ifcObjects[obj.id] = nobj
|
|
||||||
processedIds.append(obj.id)
|
|
||||||
|
|
||||||
if not IfcImport.Next():
|
if not IfcImport.Next():
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# processing non-geometry and relationships
|
# processing non-geometry and relationships
|
||||||
parents_temp = dict(ifcParents)
|
parents_temp = dict(ifcParents)
|
||||||
import ArchCommands
|
import ArchCommands
|
||||||
|
#print parents_temp
|
||||||
|
|
||||||
while parents_temp:
|
while parents_temp:
|
||||||
id, c = parents_temp.popitem()
|
id, c = parents_temp.popitem()
|
||||||
|
@ -220,42 +289,54 @@ def read(filename):
|
||||||
parent = ifcObjects[grandparent_id]
|
parent = ifcObjects[grandparent_id]
|
||||||
else:
|
else:
|
||||||
# creating parent if needed
|
# creating parent if needed
|
||||||
parent_ifcobj = IfcImport.GetObject(parent_id)
|
if IOC_ADVANCED:
|
||||||
if DEBUG: print "["+str(int((float(parent_ifcobj.id)/num_lines)*100))+"%] parsing ",parent_ifcobj.id,": ",parent_ifcobj.name," of type ",parent_ifcobj.type
|
parent_ifcobj = ifc.by_id(parent_id)
|
||||||
n = getName(parent_ifcobj)
|
parentid = int(str(obj).split("=")[0].strip("#"))
|
||||||
if parent_ifcobj.id <= 0:
|
parentname = obj.get_argument(obj.get_argument_index("Name"))
|
||||||
|
parenttype = str(obj).split("=")[1].split("(")[0]
|
||||||
|
else:
|
||||||
|
parent_ifcobj = IfcImport.GetObject(parent_id)
|
||||||
|
parentid = obj.id
|
||||||
|
parentname = obj.name
|
||||||
|
parenttype = obj.type
|
||||||
|
#if DEBUG: print "["+str(int((float(idx)/num_lines)*100))+"%] parsing ",parentid,": ",parentname," of type ",parenttype
|
||||||
|
n = getCleanName(parentname,parentid,parenttype)
|
||||||
|
if parentid <= 0:
|
||||||
parent = None
|
parent = None
|
||||||
elif parent_ifcobj.type == "IfcBuildingStorey":
|
elif parenttype == "IfcBuildingStorey":
|
||||||
parent = Arch.makeFloor(name=n)
|
parent = Arch.makeFloor(name=n)
|
||||||
parent.Label = n
|
parent.Label = n
|
||||||
elif parent_ifcobj.type == "IfcBuilding":
|
elif parenttype == "IfcBuilding":
|
||||||
parent = Arch.makeBuilding(name=n)
|
parent = Arch.makeBuilding(name=n)
|
||||||
parent.Label = n
|
parent.Label = n
|
||||||
elif parent_ifcobj.type == "IfcSite":
|
elif parenttype == "IfcSite":
|
||||||
parent = Arch.makeSite(name=n)
|
parent = Arch.makeSite(name=n)
|
||||||
parent.Label = n
|
parent.Label = n
|
||||||
elif parent_ifcobj.type == "IfcWindow":
|
elif parenttype == "IfcWindow":
|
||||||
parent = Arch.makeWindow(name=n)
|
parent = Arch.makeWindow(name=n)
|
||||||
parent.Label = n
|
parent.Label = n
|
||||||
else:
|
else:
|
||||||
if DEBUG: print "Fixme: skipping unhandled parent: ", parent_ifcobj.id, " ", parent_ifcobj.type
|
if DEBUG: print "Fixme: skipping unhandled parent: ", parentid, " ", parenttype
|
||||||
parent = None
|
parent = None
|
||||||
# registering object number and parent
|
# registering object number and parent
|
||||||
if parent_ifcobj.parent_id > 0:
|
if not IOC_ADVANCED:
|
||||||
ifcParents[parent_ifcobj.id] = [parent_ifcobj.parent_id,True]
|
if parent_ifcobj.parent_id > 0:
|
||||||
parents_temp[parent_ifcobj.id] = [parent_ifcobj.parent_id,True]
|
ifcParents[parentid] = [parent_ifcobj.parent_id,True]
|
||||||
if parent and (not parent_ifcobj.id in ifcObjects):
|
parents_temp[parentid] = [parent_ifcobj.parent_id,True]
|
||||||
ifcObjects[parent_ifcobj.id] = parent
|
if parent and (not parentid in ifcObjects):
|
||||||
|
ifcObjects[parentid] = parent
|
||||||
|
|
||||||
# attributing parent
|
# attributing parent
|
||||||
if parent and (id in ifcObjects):
|
if parent and (id in ifcObjects):
|
||||||
if ifcObjects[id]:
|
if ifcObjects[id] and (ifcObjects[id].Name != parent.Name):
|
||||||
if additive:
|
if additive:
|
||||||
|
if DEBUG: print "adding ",ifcObjects[id].Name, " to ",parent.Name
|
||||||
ArchCommands.addComponents(ifcObjects[id],parent)
|
ArchCommands.addComponents(ifcObjects[id],parent)
|
||||||
else:
|
else:
|
||||||
|
if DEBUG: print "removing ",ifcObjects[id].Name, " from ",parent.Name
|
||||||
ArchCommands.removeComponents(ifcObjects[id],parent)
|
ArchCommands.removeComponents(ifcObjects[id],parent)
|
||||||
|
if not IOC_ADVANCED:
|
||||||
IfcImport.CleanUp()
|
IfcImport.CleanUp()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# use only the internal python parser
|
# use only the internal python parser
|
||||||
|
@ -263,7 +344,6 @@ def read(filename):
|
||||||
FreeCAD.Console.PrintWarning(str(translate("Arch","IfcOpenShell not found or disabled, falling back on internal parser.\n")))
|
FreeCAD.Console.PrintWarning(str(translate("Arch","IfcOpenShell not found or disabled, falling back on internal parser.\n")))
|
||||||
schema=getSchema()
|
schema=getSchema()
|
||||||
if schema:
|
if schema:
|
||||||
if DEBUG: global ifc
|
|
||||||
if DEBUG: print "opening",filename,"..."
|
if DEBUG: print "opening",filename,"..."
|
||||||
ifc = ifcReader.IfcDocument(filename,schema=schema,debug=DEBUG)
|
ifc = ifcReader.IfcDocument(filename,schema=schema,debug=DEBUG)
|
||||||
else:
|
else:
|
||||||
|
@ -303,14 +383,16 @@ def read(filename):
|
||||||
if DEBUG: print "done processing IFC file in %s s" % ((t3-t1))
|
if DEBUG: print "done processing IFC file in %s s" % ((t3-t1))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getName(ifcobj):
|
|
||||||
|
def getCleanName(name,ifcid,ifctype):
|
||||||
"Get a clean name from an ifc object"
|
"Get a clean name from an ifc object"
|
||||||
n = ifcobj.name
|
#print "getCleanName called",name,ifcid,ifctype
|
||||||
|
n = name
|
||||||
if not n:
|
if not n:
|
||||||
n = ifcobj.type
|
n = ifctype
|
||||||
if PREFIX_NUMBERS:
|
if PREFIX_NUMBERS:
|
||||||
n = "ID"+str(ifcobj.id)+" "+n
|
n = "ID"+str(ifcid)+" "+n
|
||||||
#for c in ",.!?;:":
|
#for c in ",.!?;:":
|
||||||
# n = n.replace(c,"_")
|
# n = n.replace(c,"_")
|
||||||
return n
|
return n
|
||||||
|
@ -329,6 +411,8 @@ def makeWall(entity,shape=None,name="Wall"):
|
||||||
body.Mesh = shape
|
body.Mesh = shape
|
||||||
wall = Arch.makeWall(body,name=name)
|
wall = Arch.makeWall(body,name=name)
|
||||||
wall.Label = name
|
wall.Label = name
|
||||||
|
if IOC_ADVANCED and ADDPLACEMENT:
|
||||||
|
wall.Placement = getPlacement(getAttr(entity,"ObjectPlacement"))
|
||||||
if DEBUG: print "made wall object ",entity,":",wall
|
if DEBUG: print "made wall object ",entity,":",wall
|
||||||
return wall
|
return wall
|
||||||
|
|
||||||
|
@ -375,6 +459,8 @@ def makeWindow(entity,shape=None,name="Window"):
|
||||||
window = Arch.makeWindow(name=name)
|
window = Arch.makeWindow(name=name)
|
||||||
window.Shape = shape
|
window.Shape = shape
|
||||||
window.Label = name
|
window.Label = name
|
||||||
|
if IOC_ADVANCED and ADDPLACEMENT:
|
||||||
|
window.Placement = getPlacement(getAttr(entity,"ObjectPlacement"))
|
||||||
if DEBUG: print "made window object ",entity,":",window
|
if DEBUG: print "made window object ",entity,":",window
|
||||||
return window
|
return window
|
||||||
|
|
||||||
|
@ -422,6 +508,9 @@ def makeStructure(entity,shape=None,ifctype=None,name="Structure"):
|
||||||
structure.Role = "Slab"
|
structure.Role = "Slab"
|
||||||
elif ifctype == "IfcFooting":
|
elif ifctype == "IfcFooting":
|
||||||
structure.Role = "Foundation"
|
structure.Role = "Foundation"
|
||||||
|
print "current placement: ",shape.Placement
|
||||||
|
if IOC_ADVANCED and ADDPLACEMENT:
|
||||||
|
structure.Placement = getPlacement(getAttr(entity,"ObjectPlacement"))
|
||||||
if DEBUG: print "made structure object ",entity,":",structure," (type: ",ifctype,")"
|
if DEBUG: print "made structure object ",entity,":",structure," (type: ",ifctype,")"
|
||||||
return structure
|
return structure
|
||||||
|
|
||||||
|
@ -505,6 +594,9 @@ def makeRoof(entity,shape=None,name="Roof"):
|
||||||
|
|
||||||
def getMesh(obj):
|
def getMesh(obj):
|
||||||
"gets mesh and placement from an IfcOpenShell object"
|
"gets mesh and placement from an IfcOpenShell object"
|
||||||
|
if IOC_ADVANCED:
|
||||||
|
return None,None
|
||||||
|
print "fixme: mesh data not yet supported" # TODO implement this with OCC tessellate
|
||||||
import Mesh
|
import Mesh
|
||||||
meshdata = []
|
meshdata = []
|
||||||
print obj.mesh.faces
|
print obj.mesh.faces
|
||||||
|
@ -528,26 +620,34 @@ def getMesh(obj):
|
||||||
pl = FreeCAD.Placement(mat)
|
pl = FreeCAD.Placement(mat)
|
||||||
return me,pl
|
return me,pl
|
||||||
|
|
||||||
def getShape(obj):
|
def getShape(obj,objid):
|
||||||
"gets a shape from an IfcOpenShell object"
|
"gets a shape from an IfcOpenShell object"
|
||||||
#print "retrieving shape from obj ",obj.id
|
#print "retrieving shape from obj ",objid
|
||||||
import Part
|
import Part
|
||||||
sh=Part.Shape()
|
sh=Part.Shape()
|
||||||
try:
|
brep_data = None
|
||||||
if MAKETEMPFILES:
|
if IOC_ADVANCED:
|
||||||
import tempfile
|
try:
|
||||||
tf = tempfile.mkstemp(suffix=".brp")[1]
|
brep_data = IfcImport.create_shape(obj)
|
||||||
of = pyopen(tf,"wb")
|
except:
|
||||||
of.write(obj.mesh.brep_data)
|
print "Unable to retrieve shape data"
|
||||||
of.close()
|
else:
|
||||||
sh = Part.read(tf)
|
brep_data = obj.mesh.brep_data
|
||||||
os.remove(tf)
|
if brep_data:
|
||||||
else:
|
try:
|
||||||
sh.importBrepFromString(obj.mesh.brep_data)
|
if MAKETEMPFILES:
|
||||||
#sh = Part.makeBox(2,2,2)
|
import tempfile
|
||||||
except:
|
tf = tempfile.mkstemp(suffix=".brp")[1]
|
||||||
print "Error: malformed shape"
|
of = pyopen(tf,"wb")
|
||||||
return None
|
of.write(brep_data)
|
||||||
|
of.close()
|
||||||
|
sh = Part.read(tf)
|
||||||
|
os.remove(tf)
|
||||||
|
else:
|
||||||
|
sh.importBrepFromString(brep_data)
|
||||||
|
except:
|
||||||
|
print "Error: malformed shape"
|
||||||
|
return None
|
||||||
if not sh.Solids:
|
if not sh.Solids:
|
||||||
# try to extract a solid shape
|
# try to extract a solid shape
|
||||||
if sh.Faces:
|
if sh.Faces:
|
||||||
|
@ -559,20 +659,90 @@ def getShape(obj):
|
||||||
if solid:
|
if solid:
|
||||||
sh = solid
|
sh = solid
|
||||||
except:
|
except:
|
||||||
if DEBUG: print "failed to retrieve solid from object ",obj.id
|
if DEBUG: print "failed to retrieve solid from object ",objid
|
||||||
else:
|
else:
|
||||||
if DEBUG: print "object ", obj.id, " doesn't contain any face"
|
if DEBUG: print "object ", objid, " doesn't contain any geometry"
|
||||||
m = obj.matrix
|
if not IOC_ADVANCED:
|
||||||
mat = FreeCAD.Matrix(m[0], m[3], m[6], m[9],
|
m = obj.matrix
|
||||||
m[1], m[4], m[7], m[10],
|
mat = FreeCAD.Matrix(m[0], m[3], m[6], m[9],
|
||||||
m[2], m[5], m[8], m[11],
|
m[1], m[4], m[7], m[10],
|
||||||
0, 0, 0, 1)
|
m[2], m[5], m[8], m[11],
|
||||||
sh.Placement = FreeCAD.Placement(mat)
|
0, 0, 0, 1)
|
||||||
|
sh.Placement = FreeCAD.Placement(mat)
|
||||||
# if DEBUG: print "getting Shape from ",obj
|
# if DEBUG: print "getting Shape from ",obj
|
||||||
#print "getting shape: ",sh,sh.Solids,sh.Volume,sh.isValid(),sh.isNull()
|
#print "getting shape: ",sh,sh.Solids,sh.Volume,sh.isValid(),sh.isNull()
|
||||||
#for v in sh.Vertexes: print v.Point
|
#for v in sh.Vertexes: print v.Point
|
||||||
return sh
|
return sh
|
||||||
|
|
||||||
|
def getPlacement(entity):
|
||||||
|
"returns a placement from the given entity"
|
||||||
|
if DEBUG: print " getting placement ",entity
|
||||||
|
if not entity:
|
||||||
|
return None
|
||||||
|
if IOC_ADVANCED:
|
||||||
|
if isinstance(entity,int):
|
||||||
|
entity = ifc.by_id(entity)
|
||||||
|
entitytype = str(entity).split("=")[1].split("(")[0].upper()
|
||||||
|
entityid = int(str(entity).split("=")[0].strip("#"))
|
||||||
|
else:
|
||||||
|
entitytype = entity.type.upper()
|
||||||
|
entityid = entity.id
|
||||||
|
pl = None
|
||||||
|
if entitytype == "IFCAXIS2PLACEMENT3D":
|
||||||
|
x = getVector(getAttr(entity,"RefDirection"))
|
||||||
|
z = getVector(getAttr(entity,"Axis"))
|
||||||
|
y = z.cross(x)
|
||||||
|
loc = getVector(getAttr(entity,"Location"))
|
||||||
|
m = DraftVecUtils.getPlaneRotation(x,y,z)
|
||||||
|
pl = FreeCAD.Placement(m)
|
||||||
|
pl.move(loc)
|
||||||
|
elif entitytype == "IFCLOCALPLACEMENT":
|
||||||
|
pl = getPlacement(getAttr(entity,"PlacementRelTo"))
|
||||||
|
relpl = getPlacement(getAttr(entity,"RelativePlacement"))
|
||||||
|
if pl and relpl:
|
||||||
|
pl = relpl.multiply(pl)
|
||||||
|
elif relpl:
|
||||||
|
pl = relpl
|
||||||
|
elif entitytype == "IFCCARTESIANPOINT":
|
||||||
|
loc = getVector(entity)
|
||||||
|
pl = FreeCAD.Placement()
|
||||||
|
pl.move(loc)
|
||||||
|
if DEBUG: print " made placement for ",entityid,":",pl
|
||||||
|
return pl
|
||||||
|
|
||||||
|
def getAttr(entity,attr):
|
||||||
|
"returns the given attribute from the given entity"
|
||||||
|
if IOC_ADVANCED:
|
||||||
|
if isinstance(entity,int):
|
||||||
|
entity = ifc.by_id(entity)
|
||||||
|
i = entity.get_argument_index(attr)
|
||||||
|
return entity.get_argument(i)
|
||||||
|
else:
|
||||||
|
return getattr(entity,attr)
|
||||||
|
|
||||||
|
def getVector(entity):
|
||||||
|
"returns a vector from the given entity"
|
||||||
|
if DEBUG: print " getting point from ",entity
|
||||||
|
if IOC_ADVANCED:
|
||||||
|
if isinstance(entity,int):
|
||||||
|
entity = ifc.by_id(entity)
|
||||||
|
entitytype = str(entity).split("=")[1].split("(")[0].upper()
|
||||||
|
else:
|
||||||
|
entitytype = entity.type.upper()
|
||||||
|
if entitytype == "IFCDIRECTION":
|
||||||
|
DirectionRatios = getAttr(entity,"DirectionRatios")
|
||||||
|
if len(DirectionRatios) == 3:
|
||||||
|
return FreeCAD.Vector(tuple(DirectionRatios))
|
||||||
|
else:
|
||||||
|
return FreeCAD.Vector(tuple(DirectionRatios+[0]))
|
||||||
|
elif entitytype == "IFCCARTESIANPOINT":
|
||||||
|
Coordinates = getAttr(entity,"Coordinates")
|
||||||
|
if len(Coordinates) == 3:
|
||||||
|
return FreeCAD.Vector(tuple(Coordinates))
|
||||||
|
else:
|
||||||
|
return FreeCAD.Vector(tuple(Coordinates+[0]))
|
||||||
|
return None
|
||||||
|
|
||||||
# below is only used by the internal parser #########################################
|
# below is only used by the internal parser #########################################
|
||||||
|
|
||||||
def decode(name):
|
def decode(name):
|
||||||
|
@ -692,59 +862,25 @@ def getWire(entity,placement=None):
|
||||||
pts.append(getVector(p))
|
pts.append(getVector(p))
|
||||||
return Draft.getWire(pts,closed=True,placement=placement)
|
return Draft.getWire(pts,closed=True,placement=placement)
|
||||||
|
|
||||||
def getPlacement(entity):
|
|
||||||
"returns a placement from the given entity"
|
|
||||||
# only used by the internal parser
|
|
||||||
if DEBUG: print "getting placement ",entity
|
|
||||||
if not entity: return None
|
|
||||||
pl = None
|
|
||||||
if entity.type == "IFCAXIS2PLACEMENT3D":
|
|
||||||
x = getVector(entity.RefDirection)
|
|
||||||
z = getVector(entity.Axis)
|
|
||||||
y = z.cross(x)
|
|
||||||
loc = getVector(entity.Location)
|
|
||||||
m = DraftVecUtils.getPlaneRotation(x,y,z)
|
|
||||||
pl = FreeCAD.Placement(m)
|
|
||||||
pl.move(loc)
|
|
||||||
elif entity.type == "IFCLOCALPLACEMENT":
|
|
||||||
pl = getPlacement(entity.PlacementRelTo)
|
|
||||||
relpl = getPlacement(entity.RelativePlacement)
|
|
||||||
if pl and relpl:
|
|
||||||
pl = relpl.multiply(pl)
|
|
||||||
elif relpl:
|
|
||||||
pl = relpl
|
|
||||||
elif entity.type == "IFCCARTESIANPOINT":
|
|
||||||
loc = getVector(entity)
|
|
||||||
pl = FreeCAD.Placement()
|
|
||||||
pl.move(loc)
|
|
||||||
if DEBUG: print "made placement for",entity.id,":",pl
|
|
||||||
return pl
|
|
||||||
|
|
||||||
def getVector(entity):
|
|
||||||
"returns a vector from the given entity"
|
|
||||||
# only used by the internal parser
|
|
||||||
if DEBUG: print "getting point from",entity
|
|
||||||
if entity.type == "IFCDIRECTION":
|
|
||||||
if len(entity.DirectionRatios) == 3:
|
|
||||||
return FreeCAD.Vector(tuple(entity.DirectionRatios))
|
|
||||||
else:
|
|
||||||
return FreeCAD.Vector(tuple(entity.DirectionRatios+[0]))
|
|
||||||
elif entity.type == "IFCCARTESIANPOINT":
|
|
||||||
if len(entity.Coordinates) == 3:
|
|
||||||
return FreeCAD.Vector(tuple(entity.Coordinates))
|
|
||||||
else:
|
|
||||||
return FreeCAD.Vector(tuple(entity.Coordinates+[0]))
|
|
||||||
return None
|
|
||||||
|
|
||||||
# EXPORT ##########################################################
|
# EXPORT ##########################################################
|
||||||
|
|
||||||
def export(exportList,filename):
|
def export(exportList,filename):
|
||||||
"called when freecad exports a file"
|
"called when freecad exports a file"
|
||||||
try:
|
try:
|
||||||
import ifcWriter
|
import IfcImport
|
||||||
except:
|
except:
|
||||||
print "importIFC: ifcWriter not found or unusable. Unable to export."
|
print """importIFC: ifcOpenShell is not installed. IFC export is unavailable.
|
||||||
|
Note: IFC export currently requires an experimental version of IfcOpenShell
|
||||||
|
available from https://github.com/aothms/IfcOpenShell"""
|
||||||
return
|
return
|
||||||
|
else:
|
||||||
|
if not hasattr(IfcImport,"IfcFile"):
|
||||||
|
print """importIFC: The version of ifcOpenShell installed on this system doesn't
|
||||||
|
have IFC export capabilities. IFC export currently requires an experimental
|
||||||
|
version of IfcOpenShell available from https://github.com/aothms/IfcOpenShell"""
|
||||||
|
return
|
||||||
|
import ifcWriter
|
||||||
|
|
||||||
# creating base IFC project
|
# creating base IFC project
|
||||||
import Arch,Draft
|
import Arch,Draft
|
||||||
|
|
|
@ -200,6 +200,8 @@ def geomType(edge):
|
||||||
|
|
||||||
def isValidPath(shape):
|
def isValidPath(shape):
|
||||||
"isValidPath(shape): returns True if the shape can be used as an extrusion path"
|
"isValidPath(shape): returns True if the shape can be used as an extrusion path"
|
||||||
|
if shape.isNull():
|
||||||
|
return False
|
||||||
if shape.Faces:
|
if shape.Faces:
|
||||||
return False
|
return False
|
||||||
if len(shape.Wires) > 1:
|
if len(shape.Wires) > 1:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user