Arch: Further work on the IFC exporter, now supports windows and bldg hierarchy
This commit is contained in:
parent
50a2c1afaf
commit
5224e9a2ba
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"""
|
||||
|
|
Loading…
Reference in New Issue
Block a user