Arch: Further work on the IFC exporter, now supports windows and bldg hierarchy

This commit is contained in:
Yorik van Havre 2013-12-19 20:41:42 -02:00
parent 50a2c1afaf
commit 5224e9a2ba
5 changed files with 269 additions and 100 deletions

View File

@ -595,19 +595,26 @@ def addFixture(fixture,baseobject):
else:
FreeCAD.Console.PrintMessage(str(translate("Arch","This object has no support for fixtures")))
def getTuples(data,scale=1):
"""getTuples(data,[scale]): returns a tuple or a list of tuples from a vector
def getTuples(data,scale=1,placement=None):
"""getTuples(data,[scale,placement]): returns a tuple or a list of tuples from a vector
or from the vertices of a shape. Scale can indicate a scale factor"""
import Part
if isinstance(data,FreeCAD.Vector):
if placement:
data = placement.multVec(data)
return (data.x*scale,data.y*scale,data.z*scale)
elif isinstance(data,Part.Shape):
t = []
if len(data.Wires) == 1:
import Part,DraftGeomUtils
data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges))
for v in data.Vertexes:
t.append((v.X*scale,v.Y*scale,v.Z*scale))
verts = data.Vertexes
#verts.reverse()
for v in verts:
pt = v.Point
if placement:
pt = placement.multVec(pt)
t.append((pt.x*scale,pt.y*scale,pt.z*scale))
t.append(t[0]) # for IFC verts lists must be closed
else:
print "Arch.getTuples(): Wrong profile data"
@ -626,26 +633,67 @@ def getExtrusionData(obj,scale=1):
return None
if hasattr(obj,"Proxy"):
if hasattr(obj.Proxy,"BaseProfile") and hasattr(obj.Proxy,"ExtrusionVector"):
return getTuples(obj.Proxy.BaseProfile,scale), getTuples(obj.Proxy.ExtrusionVector,scale)
pl = FreeCAD.Placement(obj.Placement)
r = FreeCAD.Rotation(obj.Placement.Rotation)
if pl.isNull():
pl = r = None
return getTuples(obj.Proxy.BaseProfile,scale,pl), getTuples(obj.Proxy.ExtrusionVector,scale,r)
return None
def getBrepFacesData(obj,scale=1):
"""getBrepFacesData(obj,[scale]): returns a list(0) of lists(1) of lists(2), list(1) being a list
of vertices defining a loop, list(1) describing a face from one or more loops, list(0)
being the whole object made of several faces. Scale can indicate a scaling factor"""
"""getBrepFacesData(obj,[scale]): returns a list(0) of lists(1) of lists(2) of lists(3),
list(3) being a list of vertices defining a loop, list(2) describing a face from one or
more loops, list(1) being the whole solid made of several faces, list(0) being the list
of solids inside the object. Scale can indicate a scaling factor"""
if hasattr(obj,"Shape"):
if obj.Shape:
if obj.shape.isValid():
if obj.Shape.isValid():
if not obj.Shape.isNull():
s = []
for face in obj.Shape.Faces:
f = []
for wire in face.Wires:
f.append(getTuples(wire,scale))
s.append(f)
return s
sols = []
for sol in obj.Shape.Solids:
s = []
for face in obj.Shape.Faces:
f = []
for wire in face.Wires:
f.append(getTuples(wire,scale))
s.append(f)
sols.append(s)
return sols
return None
def getHost(obj,strict=True):
"""getHost(obj,[strict]): returns the host of the current object. If strict is true (default),
the host can only be an object of a higher level than the given one, or in other words, if a wall
is contained in another wall which is part of a floor, the floor is returned instead of the parent wall"""
import Draft
t = Draft.getType(obj)
for par in obj.InList:
if par.isDerivedFrom("Part::Feature"):
if strict:
if Draft.getType(par) != t:
return par
else:
return getHost(par,strict)
else:
return par
return None
def pruneIncluded(objectslist):
"""pruneIncluded(objectslist): removes from a list of Arch objects, those that are subcomponents of
another shape-based object, leaving only the top-level shapes."""
import Draft
newlist = []
for obj in objectslist:
toplevel = True
if obj.isDerivedFrom("Part::Feature"):
if not (Draft.getType(obj) in ["Window","Clone"]):
for parent in obj.InList:
if parent.isDerivedFrom("Part::Feature"):
toplevel = False
if toplevel:
newlist.append(obj)
return newlist
# command definitions ###############################################
class _CommandAdd:

View File

@ -34,6 +34,7 @@ WindowPartTypes = ["Frame","Solid panel","Glass panel"]
AllowedHosts = ["Wall","Structure","Roof"]
WindowPresets = ["Fixed", "Open 1-pane", "Open 2-pane", "Sash 2-pane",
"Sliding 2-pane", "Simple door", "Glass door"]
Roles = ["Window","Door"]
def makeWindow(baseobj=None,width=None,height=None,parts=None,name=str(translate("Arch","Window"))):
'''makeWindow(baseobj,[width,height,parts,name]): creates a window based on the
@ -341,6 +342,8 @@ def makeWindowPreset(windowtype,width,height,h1,h2,h3,w1,w2,o1,o2,placement=None
FreeCAD.ActiveDocument.recompute()
obj = makeWindow(default[0],width,height,default[1])
obj.Preset = WindowPresets.index(windowtype)+1
if "door" in windowtype:
obj.Role = "Door"
FreeCAD.ActiveDocument.recompute()
return obj
@ -578,9 +581,12 @@ class _Window(ArchComponent.Component):
obj.addProperty("App::PropertyVector","Normal","Arch",
str(translate("Arch","The normal direction of this window")))
obj.addProperty("App::PropertyInteger","Preset","Arch","")
obj.addProperty("App::PropertyEnumeration","Role","Arch",
str(translate("Arch","The role of this window")))
obj.setEditorMode("Preset",2)
self.Type = "Window"
obj.Role = Roles
obj.Proxy = self
def onChanged(self,obj,prop):

View File

@ -44,7 +44,6 @@ if not hasattr(IfcExport,"IfcFile"):
PRECISION = 4 # rounding value, in number of digits
# Basic functions #################################################################
@ -53,11 +52,11 @@ class _tempEntityHolder:
to be made into something nicer later..."""
def __init__(self):
self.refs = []
holder = _tempEntityHolder()
def new():
"""new(): returns a new empty ifc file holder"""
global holder
holder = _tempEntityHolder()
fil = IfcExport.IfcFile()
return fil
@ -104,16 +103,14 @@ def getValueAndDirection(vec):
normal = (x,y,z)
return length,normal
def create(ifcdoc,ifcname,arguments=[],refholder=None):
def create(ifcdoc,ifcname,arguments=[]):
"""create(ifcdoc,ifcname,[arguments]):creates an entity
of the given name in the given document and optionally
gives it an ordered list of arguments"""
entity = IfcExport.Entity(ifcname)
ifcdoc.add(entity)
if refholder != None:
refholder.append(entity)
else:
holder.refs.append(entity)
# this is a temporary hack while ifcopenshell has no ref counting
holder.refs.append(entity)
if not isinstance(arguments,list):
arguments = [arguments]
for i in range(len(arguments)):
@ -280,25 +277,24 @@ class IfcDocument(object):
def __init__(self,filepath="",name="",owner="",organization="",application="Python IFC exporter",version="0.0"):
self._fileobject = IfcExport.IfcFile()
self._refs = []
self._person = create(self._fileobject,"IfcPerson",[None,None,None,None,None,None,None,None],self._refs)
self._org = create(self._fileobject,"IfcOrganization",[None,"",None,None,None],self._refs)
pno = create(self._fileobject,"IfcPersonAndOrganization",[self._person,self._org,None],self._refs)
app = create(self._fileobject,"IfcApplication",[self._org,version,application,uid()],self._refs)
self._owner = create(self._fileobject,"IfcOwnerHistory",[pno,app,None,"ADDED",None,pno,app,now()],self._refs)
self._person = create(self._fileobject,"IfcPerson",[None,None,"",None,None,None,None,None])
self._org = create(self._fileobject,"IfcOrganization",[None,"",None,None,None])
pno = create(self._fileobject,"IfcPersonAndOrganization",[self._person,self._org,None])
app = create(self._fileobject,"IfcApplication",[self._org,version,application,uid()])
self._owner = create(self._fileobject,"IfcOwnerHistory",[pno,app,None,"ADDED",None,pno,app,now()])
self.Placement = self.addPlacement()
self._repcontext = create(self._fileobject,"IfcGeometricRepresentationContext",[None,'Model',3,1.E-05,self.Placement,None],self._refs)
dim1 = create(self._fileobject,"IfcDimensionalExponents",[0,0,0,0,0,0,0],self._refs)
dim2 = create(self._fileobject,"IfcSIUnit",[dim1,"LENGTHUNIT","MILLI","METRE"],self._refs)
dim3 = create(self._fileobject,"IfcSIUnit",[dim1,"AREAUNIT",None,"SQUARE_METRE"],self._refs)
dim4 = create(self._fileobject,"IfcSIUnit",[dim1,"VOLUMEUNIT",None,"CUBIC_METRE"],self._refs)
dim6 = create(self._fileobject,"IfcSIUnit",[dim1,"PLANEANGLEUNIT",None,"RADIAN"],self._refs)
dim7 = create(self._fileobject,"IfcPlaneAngleMeasure",[1.745E-2],self._refs)
dim8 = create(self._fileobject,"IfcMeasureWithUnit",[dim7,dim6],self._refs)
dim9 = create(self._fileobject,"IfcConversionBasedUnit",[dim1,"PLANEANGLEUNIT","DEGREE",dim8],self._refs)
units = create(self._fileobject,"IfcUnitAssignment",[[dim2,dim3,dim4,dim9]],self._refs)
self.Project = create(self._fileobject,"IfcProject",[uid(),self._owner,None,None,None,None,None,[self._repcontext],units],self._refs)
self._site = create(self._fileobject,"IfcSite",[uid(),self._owner,None,None,None,self.Placement,None,None,"ELEMENT",None,None,None,None,None],self._refs)
self._repcontext = create(self._fileobject,"IfcGeometricRepresentationContext",[None,'Model',3,1.E-05,self.Placement,None])
dim1 = create(self._fileobject,"IfcDimensionalExponents",[0,0,0,0,0,0,0])
dim2 = create(self._fileobject,"IfcSIUnit",[dim1,"LENGTHUNIT","MILLI","METRE"])
dim3 = create(self._fileobject,"IfcSIUnit",[dim1,"AREAUNIT",None,"SQUARE_METRE"])
dim4 = create(self._fileobject,"IfcSIUnit",[dim1,"VOLUMEUNIT",None,"CUBIC_METRE"])
dim6 = create(self._fileobject,"IfcSIUnit",[dim1,"PLANEANGLEUNIT",None,"RADIAN"])
dim7 = create(self._fileobject,"IfcPlaneAngleMeasure",[1.745E-2])
dim8 = create(self._fileobject,"IfcMeasureWithUnit",[dim7,dim6])
dim9 = create(self._fileobject,"IfcConversionBasedUnit",[dim1,"PLANEANGLEUNIT","DEGREE",dim8])
units = create(self._fileobject,"IfcUnitAssignment",[[dim2,dim3,dim4,dim9]])
self.Project = create(self._fileobject,"IfcProject",[uid(),self._owner,None,None,None,None,None,[self._repcontext],units])
self._site = create(self._fileobject,"IfcSite",[uid(),self._owner,"Site",None,None,self.Placement,None,None,"ELEMENT",None,None,None,None,None])
self._relate(self.Project,self._site)
self._storeyRelations = {}
self.BuildingProducts = []
@ -310,7 +306,7 @@ class IfcDocument(object):
self.Name = name
def __repr__(self):
return "IFC document " + self.Name + " containing " + str(len(self._refs)) + " entities"
return "IFC document " + self.Name #+ " containing " + str(len(holder)) + " entities"
def __setattr__(self,key,value):
if value:
@ -322,6 +318,16 @@ class IfcDocument(object):
elif key == "Name":
self.Project.set_argument(2,value)
self.__dict__.__setitem__(key,value)
def findByName(self,ifctype,name):
"finds an entity of a given ifctype by name"
objs = self._fileobject.by_type(ifctype)
for obj in objs:
for i in range(obj.get_argument_count()):
if obj.get_argument_name(i) == "Name":
if obj.get_argument(i) == name:
return obj
return None
def write(self,fp=None):
"writes the document to its file"
@ -343,12 +349,12 @@ class IfcDocument(object):
"""addPlacement([reference,origin,xaxis,zaxis,local]): adds a placement. origin,
xaxis and zaxis can be either tuples or 3d vectors. If local is False, a global
placement is returned, otherwise a local one."""
xvc = create(self._fileobject,"IfcDirection",getTuple(xaxis),self._refs)
zvc = create(self._fileobject,"IfcDirection",getTuple(zaxis),self._refs)
ovc = create(self._fileobject,"IfcCartesianPoint",getTuple(origin),self._refs)
gpl = create(self._fileobject,"IfcAxis2Placement3D",[ovc,zvc,xvc],self._refs)
xvc = create(self._fileobject,"IfcDirection",getTuple(xaxis))
zvc = create(self._fileobject,"IfcDirection",getTuple(zaxis))
ovc = create(self._fileobject,"IfcCartesianPoint",getTuple(origin))
gpl = create(self._fileobject,"IfcAxis2Placement3D",[ovc,zvc,xvc])
if local:
lpl = create(self._fileobject,"IfcLocalPlacement",[reference,gpl],self._refs)
lpl = create(self._fileobject,"IfcLocalPlacement",[reference,gpl])
return lpl
else:
return gpl
@ -357,7 +363,7 @@ class IfcDocument(object):
"""addBuilding([placement,name,description]): adds a building"""
if not placement:
placement = self.addPlacement()
bdg = create(self._fileobject,"IfcBuilding",[uid(),self._owner,name,description,None,placement,None,None,"ELEMENT",None,None,None],self._refs)
bdg = create(self._fileobject,"IfcBuilding",[uid(),self._owner,name,description,None,placement,None,None,"ELEMENT",None,None,None])
self._relate(self._site,bdg)
self.Buildings.append(bdg)
return bdg
@ -366,7 +372,7 @@ class IfcDocument(object):
"""addStorey([building,placement,name,description]): adds a storey"""
if not placement:
placement = self.addPlacement()
sto = create(self._fileobject,"IfcBuildingStorey",[uid(),self._owner,name,description,None,placement,None,None,"ELEMENT",None],self._refs)
sto = create(self._fileobject,"IfcBuildingStorey",[uid(),self._owner,name,description,None,placement,None,None,"ELEMENT",None])
if not building:
if self.Buildings:
building = self.Buildings[0]
@ -387,10 +393,10 @@ class IfcDocument(object):
prods = self._storeyRelations[sid].get_argument(4)
self._storeyRelations[sid].set_argument(4,prods+entities)
else:
rel = create(self._fileobject,"IfcRelContainedInSpatialStructure",[uid(),self._owner,'StoreyLink','',entities,container],self._refs)
rel = create(self._fileobject,"IfcRelContainedInSpatialStructure",[uid(),self._owner,'StoreyLink','',entities,container])
self._storeyRelations[sid] = rel
else:
create(self._fileobject,"IfcRelAggregates",[uid(),self._owner,'Relationship','',container,entities],self._refs)
create(self._fileobject,"IfcRelAggregates",[uid(),self._owner,'Relationship','',container,entities])
def addWall(self,shapes,storey=None,placement=None,name="Default wall",description=None):
"""addWall(shapes,[storey,placement,name,description]): creates a wall from the given representation shape(s)"""
@ -398,9 +404,9 @@ class IfcDocument(object):
placement = self.addPlacement()
if not isinstance(shapes,list):
shapes = [shapes]
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]],self._refs) for shape in shapes]
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps],self._refs)
wal = create(self._fileobject,"IfcWallStandardCase",[uid(),self._owner,name,description,None,placement,prd,None],self._refs)
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]]) for shape in shapes]
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
wal = create(self._fileobject,"IfcWallStandardCase",[uid(),self._owner,name,description,None,placement,prd,None])
self.BuildingProducts.append(wal)
if not storey:
if self.Storeys:
@ -411,15 +417,18 @@ class IfcDocument(object):
return wal
def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None):
"""addWall(ifctype,shapes,[storey,placement,name,description]): creates a structure
"""addStructure(ifctype,shapes,[storey,placement,name,description]): creates a structure
from the given representation shape(s). Ifctype is the type of structural object (IfcBeam, IfcColumn, etc)"""
if not placement:
placement = self.addPlacement()
if not isinstance(shapes,list):
shapes = [shapes]
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]],self._refs) for shape in shapes]
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps],self._refs)
stt = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None],self._refs)
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]]) for shape in shapes]
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
if ifctype in ["IfcSlab","IfcFooting"]:
stt = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None,"NOTDEFINED"])
else:
stt = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None])
self.BuildingProducts.append(stt)
if not storey:
if self.Storeys:
@ -428,11 +437,26 @@ class IfcDocument(object):
storey = self.addStorey()
self._relate(storey,stt)
return stt
def addWindow(self,ifctype,width,height,shapes,host=None,placement=None,name="Default Window",description=None):
"""addWindow(ifctype,width,height,shapes,[host,placement,name,description]): creates a window
from the given representation shape(s). Ifctype is the type of window object (IfcWindow, IfcDoor, etc)"""
if not placement:
placement = self.addPlacement()
if not isinstance(shapes,list):
shapes = [shapes]
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]]) for shape in shapes]
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
win = create(self._fileobject,ifctype,[uid(),self._owner,name,description,None,placement,prd,None,float(height),float(width)])
self.BuildingProducts.append(win)
if host:
self._relate(host,win)
return win
def addPolyline(self,points):
"""addPolyline(points): creates a polyline from the given points"""
pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p),self._refs) for p in points]
pol = create(self._fileobject,"IfcPolyline",[pts],self._refs)
pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p)) for p in points]
pol = create(self._fileobject,"IfcPolyline",[pts])
return pol
def addExtrusion(self,polyline,extrusion,placement=None):
@ -441,9 +465,9 @@ class IfcDocument(object):
if not placement:
placement = self.addPlacement(local=False)
value,norm = getValueAndDirection(extrusion)
edir = create(self._fileobject,"IfcDirection",[norm],self._refs)
area = create(self._fileobject,"IfcArbitraryClosedProfileDef",["AREA",None,polyline],self._refs)
solid = create(self._fileobject,"IfcExtrudedAreaSolid",[area,placement,edir,value],self._refs)
edir = create(self._fileobject,"IfcDirection",[norm])
area = create(self._fileobject,"IfcArbitraryClosedProfileDef",["AREA",None,polyline])
solid = create(self._fileobject,"IfcExtrudedAreaSolid",[area,placement,edir,value])
return solid
def addExtrudedPolyline(self,points,extrusion,placement=None):
@ -456,29 +480,42 @@ class IfcDocument(object):
def addFace(self,face):
"""addFace(face): creates a face from the given face data (a list of lists of points).
The first is the outer wire, the next are optional inner wires. They must be reversed in order"""
pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p),self._refs) for p in face[0]]
loop = create(self._fileobject,"IfcPolyLoop",[pts],self._refs)
ofb = create(self._fileobject,"IfcFaceOuterBound",[loop,True],self._refs)
ifb = []
for f in face[1:]:
pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p),self._refs) for p in f]
loop = create(self._fileobject,"IfcPolyLoop",[pts],self._refs)
fb = create(self._fileobject,"IfcFaceBound",[loop,True],self._refs)
idx = 0
for f in face:
pts = []
for p in f:
#print p
if p in self.fpoints:
#print self.fpoints.index(p)
#print self.frefs
pts.append(self.frefs[self.fpoints.index(p)])
else:
pt = create(self._fileobject,"IfcCartesianPoint",getTuple(p))
pts.append(pt)
self.fpoints.append(p)
self.frefs.append(pt)
#print pts
loop = create(self._fileobject,"IfcPolyLoop",[pts])
if idx == 0:
fb = create(self._fileobject,"IfcFaceOuterBound",[loop,True])
else:
fb = create(self._fileobject,"IfcFaceBound",[loop,True])
ifb.append(fb)
#print [ofb]+ifb
#print dir(ofb)
#for i in range(ofb.get_argument_count()):
# print i,": ",ofb.get_argument_name(i)
# 0 : Bound, 1 : Orientation
iface = create(self._fileobject,"IfcFace",[[ofb]+ifb],self._refs)
idx += 1
iface = create(self._fileobject,"IfcFace",[ifb])
return iface
def addFacetedBrep(self,faces):
"""addFacetedBrep(self,faces): creates a faceted brep object from the given list
of faces (each face is a list of lists of points, inner wires are reversed)"""
self.fpoints = []
self.frefs = []
#print "adding ",len(faces)," faces"
#print faces
ifaces = [self.addFace(face) for face in faces]
sh = create(self._fileobject,"IfcClosedShell",[ifaces],self._refs)
brp = create(self._fileobject,"IfcFacetedBrep",[sh],self._refs)
sh = create(self._fileobject,"IfcClosedShell",[ifaces])
brp = create(self._fileobject,"IfcFacetedBrep",[sh])
return brp
@ -526,7 +563,7 @@ def example2():
ifc.Name = "Test Project"
ifc.Owner = "Yorik van Havre"
ifc.Organization = "FreeCAD"
ifc.addWall( ifc.addExtrudedPolyline([(0,0,0),(0,200,0),(5000,200,0),(5000,0,0),(0,0,0)], (0,0,3500)) )
w1 = ifc.addWall( ifc.addExtrudedPolyline([(0,0,0),(0,200,0),(5000,200,0),(5000,0,0),(0,0,0)], (0,0,3500)) )
ifc.addWall( ifc.addExtrudedPolyline([(0,200,0),(0,2000,0),(200,2000,0),(200,200,0),(0,200,0)],(0,0,3500)) )
ifc.addWall( ifc.addExtrudedPolyline([(0,2000,0),(0,2200,0),(5000,2200,0),(5000,2000,0),(0,2000,0)],(0,0,3500)) )
ifc.addWall( ifc.addExtrudedPolyline([(5000,200,0),(5000,2000,0),(4800,2000,0),(4800,200,0),(5000,200,0)],(0,0,3500)) )
@ -537,5 +574,15 @@ def example2():
[[(100,-1000,0),(100,-1000,1000),(100,0,1000),(100,0,0)]],
[[(0,0,1000),(0,-1000,1000),(100,-1000,1000),(100,0,1000)]]]) )
ifc.addStructure( "IfcColumn", ifc.addExtrudedPolyline([(0,0,0),(0,-200,0),(-500,-200,0),(-500,0,0),(0,0,0)], (0,0,3500)) )
ifc.addWindow( "IfcDoor", 200, 200, ifc.addExtrudedPolyline([(200,200,0),(200,400,0),(400,400,0),(400,200,0),(200,200,0)], (0,0,200)), w1 )
ifc.write()
print dir(ifc._fileobject)
print ifc._fileobject.by_type("IfcDoor")
w = ifc._fileobject.by_type("IfcDoor")[0]
print w
print dir(w)
print w.is_a("IfcDoor")
for i in range(w.get_argument_count()):
print i,": ",w.get_argument_name(i)," : ",w.get_argument(i)

View File

@ -100,6 +100,8 @@ def read(filename):
t1 = time.time()
num_lines = sum(1 for line in pyopen(filename))
processedIds = []
if getIfcOpenShell() and not FORCE_PYTHON_PARSER:
# use the IfcOpenShell parser
@ -132,6 +134,10 @@ def read(filename):
if obj.type 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 obj.id in processedIds:
if DEBUG: print "skipping because this object was already processed"
else:
# build shape
@ -186,6 +192,7 @@ def read(filename):
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():
break
@ -739,7 +746,9 @@ def export(exportList,filename):
print "IFC export: ifcWriter not found or unusable"
return
# creating base IFC project
import Arch,Draft
getConfig()
ifcWriter.PRECISION = Draft.precision()
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
scaling = p.GetFloat("IfcScalingFactor",1.0)
@ -750,26 +759,57 @@ def export(exportList,filename):
company = FreeCAD.ActiveDocument.Company
project = FreeCAD.ActiveDocument.Name
ifc = ifcWriter.IfcDocument(filename,project,owner,company,application,version)
print "opened ",ifc
for obj in exportList:
# get all children and reorder list to get buildings and floors processed first
objectslist = Draft.getGroupContents(exportList,walls=True,addgroups=True)
objectslist = Arch.pruneIncluded(objectslist)
buildings = []
floors = []
others = []
for obj in objectslist:
otype = Draft.getType(obj)
name = obj.Name
if otype == "Building":
buildings.append(obj)
elif otype == "Floor":
floors.append(obj)
else:
others.append(obj)
objectslist = buildings + floors + others
if DEBUG: print "adding ", len(objectslist), " objects"
# process objects
for obj in objectslist:
if DEBUG: print "adding ",obj.Label
otype = Draft.getType(obj)
name = str(obj.Label)
parent = Arch.getHost(obj)
gdata = Arch.getExtrusionData(obj,scaling)
if not gdata:
fdata = Arch.getBrepFacesData(obj,scaling)
if not fdata:
print "IFC export: error retrieving the shape of object ", obj.Name
continue
if not fdata:
if obj.isDerivedFrom("Part::Feature"):
print "IFC export: error retrieving the shape of object ", obj.Name
continue
if otype == "Building":
ifc.addBuilding( name=name )
if otype == "Wall":
elif otype == "Floor":
if parent:
parent = ifc.findByName("IfcBuilding",str(parent.Label))
ifc.addStorey( building=parent, name=name )
elif otype == "Wall":
if parent:
parent = ifc.findByName("IfcBuildingStorey",str(parent.Label))
if gdata:
ifc.addWall( ifc.addExtrudedPolyline(gdata[0],gdata[1]), name )
ifc.addWall( ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name )
elif fdata:
ifc.addWall( ifc.addFacetedBrep(fdata), name )
ifc.addWall( [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
elif otype == "Structure":
if parent:
parent = ifc.findByName("IfcBuildingStorey",str(parent.Label))
role = "IfcBeam"
if hasattr(obj,"Role"):
if obj.Role == "Column":
@ -779,12 +819,30 @@ def export(exportList,filename):
elif obj.Role == "Foundation":
role = "IfcFooting"
if gdata:
ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), name )
ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name )
elif fdata:
ifc.addStructure( role, ifc.addFacetedBrep(fdata), name )
ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name )
elif otype == "Window":
if parent:
p = ifc.findByName("IfcWallStandardCase",str(parent.Label))
if not p:
p = ifc.findByName("IfcColumn",str(parent.Label))
if not p:
p = ifc.findByName("IfcBeam",str(parent.Label))
if not p:
p = ifc.findByName("IfcSlab",str(parent.Label))
parent = p
role = "IfcWindow"
if hasattr(obj,"Role"):
if obj.Role == "Door":
role = "IfcDoor"
if gdata:
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.addExtrudedPolyline(gdata[0],gdata[1]), host=parent, name=name )
elif fdata:
ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, [ifc.addFacetedBrep(f) for f in fdata], host=parent, name=name )
else:
print "IFC export: object type ", otype, " is not supported yet."
ifc.write()
print "Successfully exported ",filename

View File

@ -302,27 +302,37 @@ def shapify(obj):
FreeCAD.ActiveDocument.recompute()
return newobj
def getGroupContents(objectslist,walls=False):
'''getGroupContents(objectlist): if any object of the given list
is a group, its content is appened to the list, which is returned'''
def getGroupContents(objectslist,walls=False,addgroups=False):
'''getGroupContents(objectlist,[walls,addgroups]): if any object of the given list
is a group, its content is appened to the list, which is returned. If walls is True,
walls are also scanned for included windows. If addgroups is true, the group itself
is also included in the list.'''
newlist = []
if not isinstance(objectslist,list):
objectslist = [objectslist]
for obj in objectslist:
if obj.isDerivedFrom("App::DocumentObjectGroup"):
if obj.isDerivedFrom("Drawing::FeaturePage"):
# skip if the grou is a page
# skip if the group is a page
newlist.append(obj)
else:
newlist.extend(getGroupContents(obj.Group))
if addgroups:
newlist.append(obj)
newlist.extend(getGroupContents(obj.Group,walls,addgroups))
else:
#print "adding ",obj.Name
newlist.append(obj)
if walls:
if getType(obj) == "Wall":
for o in obj.OutList:
if (getType(o) == "Window") or isClone(o,"Window"):
newlist.append(o)
return newlist
# cleaning possible duplicates
cleanlist = []
for obj in newlist:
if not obj in cleanlist:
cleanlist.append(obj)
return cleanlist
def removeHidden(objectslist):
"""removeHidden(objectslist): removes hidden objects from the list"""