From dcc81c513d66eb5a1736e63323669684bb204206 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 23 Apr 2014 15:51:59 -0300 Subject: [PATCH] Arch: Support of circle-based extrusions in IFC export --- src/Mod/Arch/ArchCommands.py | 6 ++- src/Mod/Arch/ifcWriter.py | 29 ++++++++++---- src/Mod/Arch/importIFC.py | 76 ++++++++++++++++++++++++++++++------ 3 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index 85b74808d..abf325a8c 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -649,11 +649,15 @@ def getExtrusionData(obj,scale=1): return None if hasattr(obj,"Proxy"): if hasattr(obj.Proxy,"BaseProfile") and hasattr(obj.Proxy,"ExtrusionVector"): + import Part 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) + if len(obj.Proxy.BaseProfile.Edges) == 1: + if isinstance(obj.Proxy.BaseProfile.Edges[0].Curve,Part.Circle): + return "circle", getTuples(obj.Proxy.BaseProfile.Edges[0].Curve.Center,scale), obj.Proxy.BaseProfile.Edges[0].Curve.Radius*scale, getTuples(obj.Proxy.ExtrusionVector,scale,r) + return "polyline", getTuples(obj.Proxy.BaseProfile,scale,pl), getTuples(obj.Proxy.ExtrusionVector,scale,r) return None def getBrepFacesData(obj,scale=1): diff --git a/src/Mod/Arch/ifcWriter.py b/src/Mod/Arch/ifcWriter.py index 9f2581b8b..6b0e44787 100644 --- a/src/Mod/Arch/ifcWriter.py +++ b/src/Mod/Arch/ifcWriter.py @@ -463,14 +463,14 @@ class IfcDocument(object): self._relate(storey,wal) return wal - def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None,standard=False): + def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None,extrusion=False): """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] - if standard: + if extrusion: solidType = "SweptSolid" else: solidType = "Brep" @@ -508,17 +508,23 @@ class IfcDocument(object): """addPolyline(points): creates a polyline from the given points""" pts = [create(self._fileobject,"IfcCartesianPoint",getTuple(p)) for p in points] pol = create(self._fileobject,"IfcPolyline",[pts]) - return pol + area = create(self._fileobject,"IfcArbitraryClosedProfileDef",["AREA",None,pol]) + return area + + def addCircle(self,radius): + """addCircle(radius): creates a polyline from the given points""" + lpl = self.addPlacement() + cir = create(self._fileobject,"IfcCircleProfileDef",["AREA",None,lpl,float(radius)]) + return cir - def addExtrusion(self,polyline,extrusion,placement=None): - """addExtrusion(polyline,extrusion,[placement]): makes an + def addExtrusion(self,profile,extrusion,placement=None): + """addExtrusion(profile,extrusion,[placement]): makes an extrusion of the given polyline with the given extrusion vector""" if not placement: placement = self.addPlacement(local=False) value,norm = getValueAndDirection(extrusion) edir = create(self._fileobject,"IfcDirection",[norm]) - area = create(self._fileobject,"IfcArbitraryClosedProfileDef",["AREA",None,polyline]) - solid = create(self._fileobject,"IfcExtrudedAreaSolid",[area,placement,edir,value]) + solid = create(self._fileobject,"IfcExtrudedAreaSolid",[profile,placement,edir,value]) return solid def addExtrudedPolyline(self,points,extrusion,placement=None): @@ -527,6 +533,15 @@ class IfcDocument(object): pol = self.addPolyline(points) exp = self.addExtrusion(pol,extrusion,placement) return exp + + def addExtrudedCircle(self,center,radius,extrusion,placement=None): + """addExtrudedCircle(radius,extrusion,[placement]): makes an extruded circle + from the given radius and the given extrusion vector""" + cir = self.addCircle(radius) + if not placement: + placement = self.addPlacement(origin=center) + exp = self.addExtrusion(cir,extrusion,placement) + return exp def addFace(self,face): """addFace(face): creates a face from the given face data (a list of lists of points). diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 16ce257c6..44a4bc199 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -34,6 +34,7 @@ SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1. MAKETEMPFILES = False # if True, shapes are passed from ifcopenshell to freecad through temp files DEBUG = True # this is only for the python console, this value is overridden when importing through the GUI SKIP = ["IfcBuildingElementProxy","IfcFlowTerminal","IfcFurnishingElement"] # default. overwritten by the GUI options +TOUCH = True # arch objects based on profiles need to be reexecuted after loading the file (this is temporary) # end config if open.__module__ == '__builtin__': @@ -923,9 +924,9 @@ def export(exportList,filename): version of IfcOpenShell available from https://github.com/aothms/IfcOpenShell""" return import ifcWriter + import Arch,Draft # creating base IFC project - import Arch,Draft getConfig() ifcWriter.PRECISION = Draft.precision() p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") @@ -944,6 +945,13 @@ def export(exportList,filename): # 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) + + # workaround: loaded objects loose their profile info - needs to recompute... + if TOUCH: + for o in objectslist: + if Draft.getType(o) in ["Wall", "Structure"]: + o.Proxy.execute(o) + buildings = [] floors = [] others = [] @@ -971,20 +979,45 @@ def export(exportList,filename): if DEBUG: print "adding ",obj.Label + # getting geometry if not forcebrep: gdata = Arch.getExtrusionData(obj,scaling) #if DEBUG: print "extrusion data for ",obj.Label," : ",gdata if not gdata: fdata = Arch.getBrepFacesData(obj,scaling) #if DEBUG: print "brep data for ",obj.Label," : ",fdata - if DEBUG: print " Brep" if not fdata: if obj.isDerivedFrom("Part::Feature"): print "IFC export: error retrieving the shape of object ", obj.Name continue + else: + if DEBUG: print " No geometry" + else: + if DEBUG: print " Brep" else: if DEBUG: print " Extrusion" + # compute final placement + basepoint = None + if obj.isDerivedFrom("Part::Feature"): + b1 = None + b2 = None + if hasattr(obj,"Base"): + if obj.Base: + b1 = FreeCAD.Vector(obj.Base.Placement.Base).multiply(scaling) + if hasattr(obj,"Placement"): + b2 = FreeCAD.Vector(obj.Placement.Base).multiply(scaling) + if b2: + if b1: + basepoint = b2.add(b1) + else: + basepoint = b2 + elif b1: + basepoint = b1 + if basepoint: + basepoint = Arch.getTuples(basepoint) + + # writing text log spacer = "" for i in range(36-len(obj.Label)): spacer += " " @@ -996,7 +1029,8 @@ def export(exportList,filename): else: tp = otype txt.append(obj.Label + spacer + tp) - + + # writing IFC data if otype == "Building": ifc.addBuilding( name=name ) @@ -1009,11 +1043,15 @@ def export(exportList,filename): if parent: parent = ifc.findByName("IfcBuildingStorey",str(parent.Label)) if gdata: - ifc.addWall( ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name, standard=True ) + if gdata[0] == "polyline": + ifc.addWall( ifc.addExtrudedPolyline(gdata[1], gdata[2]), storey=parent, name=name, standard=True ) + elif gdata[0] == "circle": + ifc.addWall( ifc.addExtrudedCircle(gdata[1], gdata[2], gdata[3]), storey=parent, name=name ) elif fdata: ifc.addWall( [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name ) elif otype == "Structure": + placement = None if parent: parent = ifc.findByName("IfcBuildingStorey",str(parent.Label)) role = "IfcBeam" @@ -1025,13 +1063,24 @@ def export(exportList,filename): elif obj.Role == "Foundation": role = "IfcFooting" if gdata: - #ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name ) - if FreeCAD.Vector(gdata[1]).getAngle(FreeCAD.Vector(0,0,1)) < .01: - # Workaround for non-Z extrusions, apparently not supported by ifc++ TODO: fix this - ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name, standard=True ) - else: - fdata = Arch.getBrepFacesData(obj,scaling) - ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name ) + if gdata[0] == "polyline": + #ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[0],gdata[1]), storey=parent, name=name ) + if FreeCAD.Vector(gdata[2]).getAngle(FreeCAD.Vector(0,0,1)) < .01: + # the placement of polylines is weird... The Z values from the polyline info is not used, + # so we need to give it now as a placement. + if basepoint: + if round(basepoint[2],Draft.precision()) != 0: + placement = ifc.addPlacement(origin=(0.0,0.0,basepoint[2])) + ifc.addStructure( role, ifc.addExtrudedPolyline(gdata[1],gdata[2]), storey=parent, placement=placement, name=name, extrusion=True ) + else: + # Workaround for non-Z extrusions, apparently not supported by ifc++ TODO: fix this + print " switching to Brep" + fdata = Arch.getBrepFacesData(obj,scaling) + ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name ) + elif gdata[0] == "circle": + if basepoint: + placement = ifc.addPlacement(origin=basepoint) + ifc.addStructure( role, ifc.addExtrudedCircle(gdata[1], gdata[2], gdata[3]), storey=parent, placement=placement, name=name, extrusion=True ) elif fdata: ifc.addStructure( role, [ifc.addFacetedBrep(f) for f in fdata], storey=parent, name=name ) @@ -1052,7 +1101,8 @@ def export(exportList,filename): 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 ) + if gdata[0] == "polyline": + ifc.addWindow( role, obj.Width*scaling, obj.Height*scaling, ifc.addExtrudedPolyline(gdata[1], gdata[2]), 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 ) @@ -1082,6 +1132,8 @@ def export(exportList,filename): f.write(txtstring) f.close() + FreeCAD.ActiveDocument.recompute() + def explore(filename=None): "explore the contents of an ifc file in a Qt dialog"