diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index ba777575b..f92ebecfe 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -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: diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index b0c0062e8..efe46eb68 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -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): diff --git a/src/Mod/Arch/ifcWriter.py b/src/Mod/Arch/ifcWriter.py index 1f2d52355..977b35cfe 100644 --- a/src/Mod/Arch/ifcWriter.py +++ b/src/Mod/Arch/ifcWriter.py @@ -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) diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 7f235c48b..631128bc9 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -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 diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 4ad4b40de..046059aef 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -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"""