Arch: Better sticking to standards in IFC import/export
This commit is contained in:
parent
8609337d6f
commit
cd7c1f2307
|
@ -602,7 +602,7 @@ def addFixture(fixture,baseobject):
|
|||
else:
|
||||
FreeCAD.Console.PrintMessage(translate("Arch","This object has no support for fixtures"))
|
||||
|
||||
def getTuples(data,scale=1,placement=None,normal=None):
|
||||
def getTuples(data,scale=1,placement=None,normal=None,close=True):
|
||||
"""getTuples(data,[scale,placement,normal]): 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
|
||||
|
@ -630,6 +630,7 @@ def getTuples(data,scale=1,placement=None,normal=None):
|
|||
if placement:
|
||||
pt = placement.multVec(pt)
|
||||
t.append((pt.x*scale,pt.y*scale,pt.z*scale))
|
||||
if close:
|
||||
t.append(t[0]) # for IFC verts lists must be closed
|
||||
else:
|
||||
print "Arch.getTuples(): Wrong profile data"
|
||||
|
@ -669,10 +670,10 @@ def getBrepFacesData(obj,scale=1):
|
|||
s = []
|
||||
for face in obj.Shape.Faces:
|
||||
f = []
|
||||
f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0)))
|
||||
f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False))
|
||||
for wire in face.Wires:
|
||||
if wire.hashCode() != face.OuterWire.hashCode():
|
||||
f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0))))
|
||||
f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False))
|
||||
s.append(f)
|
||||
sols.append(s)
|
||||
return sols
|
||||
|
|
|
@ -240,7 +240,7 @@ def makeWall(ifcdoc,storey,owner,context,shape,placement=None,name="Default wall
|
|||
in the given ifc document"""
|
||||
if not placement:
|
||||
placement = makePlacement(ifcdoc)
|
||||
rep = create(ifcdoc,"IfcShapeRepresentation",[context,'Body','SweptSolid',[shape]])
|
||||
rep = create(ifcdoc,"IfcShapeRepresentation",[context,'Body','SolidModel',[shape]])
|
||||
prd = create(ifcdoc,"IfcProductDefinitionShape",[None,None,[rep]])
|
||||
wal = create(ifcdoc,"IfcWallStandardCase",[uid(),owner,name,description,
|
||||
None,placement,prd,None])
|
||||
|
@ -375,6 +375,9 @@ class IfcDocument(object):
|
|||
elif "FILE_NAME" in l:
|
||||
# bug 4: incomplete file name entry
|
||||
l = l.replace("FILE_NAME('','',(''),('',''),'IfcOpenShell','IfcOpenShell','');","FILE_NAME('"+path+"','"+now(string=True)+"',('"+self.Owner+"'),('',''),'IfcOpenShell','IfcOpenShell','');")
|
||||
elif "IFCSIUNIT" in l:
|
||||
# bug 5: no way to insert * character
|
||||
l = l.replace("IFCSIUNIT(#13,","IFCSIUNIT(*,")
|
||||
lines.append(l)
|
||||
f.close()
|
||||
f = open(path,"wb")
|
||||
|
@ -441,7 +444,11 @@ class IfcDocument(object):
|
|||
placement = self.addPlacement()
|
||||
if not isinstance(shapes,list):
|
||||
shapes = [shapes]
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]]) for shape in shapes]
|
||||
if standard:
|
||||
solidType = "SweptSolid"
|
||||
else:
|
||||
solidType = "Brep"
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body',solidType,[shape]]) for shape in shapes]
|
||||
prd = create(self._fileobject,"IfcProductDefinitionShape",[None,None,reps])
|
||||
if standard:
|
||||
wal = create(self._fileobject,"IfcWallStandardCase",[uid(),self._owner,name,description,None,placement,prd,None])
|
||||
|
@ -456,14 +463,18 @@ class IfcDocument(object):
|
|||
self._relate(storey,wal)
|
||||
return wal
|
||||
|
||||
def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None):
|
||||
def addStructure(self,ifctype,shapes,storey=None,placement=None,name="Default Structure",description=None,standard=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]
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]]) for shape in shapes]
|
||||
if standard:
|
||||
solidType = "SweptSolid"
|
||||
else:
|
||||
solidType = "Brep"
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body',solidType,[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"])
|
||||
|
@ -485,7 +496,7 @@ class IfcDocument(object):
|
|||
placement = self.addPlacement()
|
||||
if not isinstance(shapes,list):
|
||||
shapes = [shapes]
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SweptSolid',[shape]]) for shape in shapes]
|
||||
reps = [create(self._fileobject,"IfcShapeRepresentation",[self._repcontext,'Body','SolidModel',[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)
|
||||
|
|
|
@ -30,8 +30,10 @@ __url__ = "http://www.freecadweb.org"
|
|||
|
||||
# config
|
||||
subtractiveTypes = ["IfcOpeningElement"] # elements that must be subtracted from their parents
|
||||
SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.exp"
|
||||
SCHEMA = "http://www.steptools.com/support/stdev_docs/express/ifc2x3/ifc2x3_tc1.exp" # only for internal prser
|
||||
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
|
||||
# end config
|
||||
|
||||
if open.__module__ == '__builtin__':
|
||||
|
@ -60,11 +62,9 @@ def insert(filename,docname,skip=None):
|
|||
|
||||
def getConfig():
|
||||
"Gets Arch IFC import preferences"
|
||||
global CREATE_IFC_GROUPS, ASMESH, DEBUG, SKIP, PREFIX_NUMBERS, FORCE_PYTHON_PARSER, SEPARATE_OPENINGS, SEPARATE_PLACEMENTS
|
||||
global CREATE_IFC_GROUPS, ASMESH, PREFIX_NUMBERS, FORCE_PYTHON_PARSER, SEPARATE_OPENINGS, SEPARATE_PLACEMENTS
|
||||
CREATE_IFC_GROUPS = False
|
||||
IMPORT_IFC_FURNITURE = False
|
||||
DEBUG = False
|
||||
SKIP = ["IfcBuildingElementProxy","IfcFlowTerminal","IfcFurnishingElement"]
|
||||
ASMESH = ["IfcFurnishingElement"]
|
||||
PREFIX_NUMBERS = False
|
||||
FORCE_PYTHON_PARSER = False
|
||||
|
@ -197,17 +197,17 @@ def read(filename,skip=None):
|
|||
|
||||
# skip IDs
|
||||
if objid in skipIds:
|
||||
if DEBUG: print "skipping because object ID is in skip list"
|
||||
if DEBUG: print " skipping because object ID is in skip list"
|
||||
nobj = None
|
||||
|
||||
# skip types
|
||||
elif objtype in SKIP:
|
||||
if DEBUG: print "skipping because type is in skip list"
|
||||
if DEBUG: print " skipping because type is in skip list"
|
||||
nobj = None
|
||||
|
||||
# check if object was already processed, to workaround an ifcopenshell bug
|
||||
elif objid in processedIds:
|
||||
if DEBUG: print "skipping because this object was already processed"
|
||||
if DEBUG: print " skipping because this object was already processed"
|
||||
|
||||
else:
|
||||
# build shape
|
||||
|
@ -318,12 +318,12 @@ def read(filename,skip=None):
|
|||
else:
|
||||
# creating parent if needed
|
||||
if IFCOPENSHELL5:
|
||||
parent_ifcobj = ifc.by_id(parent_id)
|
||||
obj = ifc.by_id(parent_id)
|
||||
parentid = int(str(obj).split("=")[0].strip("#"))
|
||||
parentname = obj.get_argument(obj.get_argument_index("Name"))
|
||||
parenttype = str(obj).split("=")[1].split("(")[0]
|
||||
else:
|
||||
parent_ifcobj = IfcImport.GetObject(parent_id)
|
||||
obj = IfcImport.GetObject(parent_id)
|
||||
parentid = obj.id
|
||||
parentname = obj.name
|
||||
parenttype = obj.type
|
||||
|
@ -343,6 +343,8 @@ def read(filename,skip=None):
|
|||
elif parenttype == "IfcWindow":
|
||||
parent = Arch.makeWindow(name=n)
|
||||
parent.Label = n
|
||||
elif parenttype == "IfcProject":
|
||||
parent = None
|
||||
else:
|
||||
if DEBUG: print "Fixme: skipping unhandled parent: ", parentid, " ", parenttype
|
||||
parent = None
|
||||
|
@ -440,24 +442,24 @@ def makeWall(entity,shape=None,name="Wall"):
|
|||
body.Mesh = shape
|
||||
wall = Arch.makeWall(body,name=name)
|
||||
wall.Label = name
|
||||
if DEBUG: print "made wall object ",entity,":",wall
|
||||
if DEBUG: print " made wall object ",entity,":",wall
|
||||
return wall
|
||||
|
||||
# use internal parser
|
||||
if DEBUG: print "=====> making wall",entity.id
|
||||
placement = wall = wire = body = width = height = None
|
||||
placement = getPlacement(entity.ObjectPlacement)
|
||||
if DEBUG: print "got wall placement",entity.id,":",placement
|
||||
if DEBUG: print " got wall placement",entity.id,":",placement
|
||||
width = entity.getProperty("Width")
|
||||
height = entity.getProperty("Height")
|
||||
if width and height:
|
||||
if DEBUG: print "got width, height ",entity.id,":",width,"/",height
|
||||
if DEBUG: print " got width, height ",entity.id,":",width,"/",height
|
||||
for r in entity.Representation.Representations:
|
||||
if r.RepresentationIdentifier == "Axis":
|
||||
wire = getWire(r.Items,placement)
|
||||
wall = Arch.makeWall(wire,width,height,align="Center",name="Wall"+str(entity.id))
|
||||
else:
|
||||
if DEBUG: print "no height or width properties found..."
|
||||
if DEBUG: print " no height or width properties found..."
|
||||
for r in entity.Representation.Representations:
|
||||
if r.RepresentationIdentifier == "Body":
|
||||
for b in r.Items:
|
||||
|
@ -468,12 +470,12 @@ def makeWall(entity,shape=None,name="Wall"):
|
|||
wall = Arch.makeWall(wire,width=0,height=b.Depth,name="Wall"+str(entity.id))
|
||||
wall.Normal = norm
|
||||
if wall:
|
||||
if DEBUG: print "made wall object ",entity.id,":",wall
|
||||
if DEBUG: print " made wall object ",entity.id,":",wall
|
||||
return wall
|
||||
if DEBUG: print "error: skipping wall",entity.id
|
||||
if DEBUG: print " error: skipping wall",entity.id
|
||||
return None
|
||||
except:
|
||||
if DEBUG: print "error: skipping wall",entity
|
||||
if DEBUG: print " error: skipping wall",entity
|
||||
return None
|
||||
|
||||
|
||||
|
@ -486,7 +488,7 @@ def makeWindow(entity,shape=None,name="Window"):
|
|||
window = Arch.makeWindow(name=name)
|
||||
window.Shape = shape
|
||||
window.Label = name
|
||||
if DEBUG: print "made window object ",entity,":",window
|
||||
if DEBUG: print " made window object ",entity,":",window
|
||||
return window
|
||||
|
||||
# use internal parser
|
||||
|
@ -503,12 +505,12 @@ def makeWindow(entity,shape=None,name="Window"):
|
|||
wire = getWire(b.SweptArea,placement)
|
||||
window = Arch.makeWindow(wire,width=b.Depth,name=objtype+str(entity.id))
|
||||
if window:
|
||||
if DEBUG: print "made window object ",entity.id,":",window
|
||||
if DEBUG: print " made window object ",entity.id,":",window
|
||||
return window
|
||||
if DEBUG: print "error: skipping window",entity.id
|
||||
if DEBUG: print " error: skipping window",entity.id
|
||||
return None
|
||||
except:
|
||||
if DEBUG: print "error: skipping window",entity
|
||||
if DEBUG: print " error: skipping window",entity
|
||||
return None
|
||||
|
||||
|
||||
|
@ -533,7 +535,7 @@ def makeStructure(entity,shape=None,ifctype=None,name="Structure"):
|
|||
structure.Role = "Slab"
|
||||
elif ifctype == "IfcFooting":
|
||||
structure.Role = "Foundation"
|
||||
if DEBUG: print "made structure object ",entity,":",structure," (type: ",ifctype,")"
|
||||
if DEBUG: print " made structure object ",entity,":",structure," (type: ",ifctype,")"
|
||||
return structure
|
||||
|
||||
# use internal parser
|
||||
|
@ -550,12 +552,12 @@ def makeStructure(entity,shape=None,ifctype=None,name="Structure"):
|
|||
wire = getWire(b.SweptArea,placement)
|
||||
structure = Arch.makeStructure(wire,height=b.Depth,name=objtype+str(entity.id))
|
||||
if structure:
|
||||
if DEBUG: print "made structure object ",entity.id,":",structure
|
||||
if DEBUG: print " made structure object ",entity.id,":",structure
|
||||
return structure
|
||||
if DEBUG: print "error: skipping structure",entity.id
|
||||
if DEBUG: print " error: skipping structure",entity.id
|
||||
return None
|
||||
except:
|
||||
if DEBUG: print "error: skipping structure",entity
|
||||
if DEBUG: print " error: skipping structure",entity
|
||||
return None
|
||||
|
||||
|
||||
|
@ -575,7 +577,7 @@ def makeSite(entity,shape=None,name="Site"):
|
|||
site.Label = name
|
||||
if body:
|
||||
site.Terrain = body
|
||||
if DEBUG: print "made site object ",entity,":",site
|
||||
if DEBUG: print " made site object ",entity,":",site
|
||||
return site
|
||||
except:
|
||||
return None
|
||||
|
@ -592,7 +594,7 @@ def makeSpace(entity,shape=None,name="Space"):
|
|||
body.Shape = shape
|
||||
space.Base = body
|
||||
body.ViewObject.hide()
|
||||
if DEBUG: print "made space object ",entity,":",space
|
||||
if DEBUG: print " made space object ",entity,":",space
|
||||
return space
|
||||
except:
|
||||
return None
|
||||
|
@ -607,7 +609,7 @@ def makeRoof(entity,shape=None,name="Roof"):
|
|||
roof = Arch.makeRoof(name=name)
|
||||
roof.Label = name
|
||||
roof.Shape = shape
|
||||
if DEBUG: print "made roof object ",entity,":",roof
|
||||
if DEBUG: print " made roof object ",entity,":",roof
|
||||
return roof
|
||||
except:
|
||||
return None
|
||||
|
@ -677,7 +679,7 @@ def getShape(obj,objid):
|
|||
else:
|
||||
sh.importBrepFromString(brep_data)
|
||||
except:
|
||||
print "Error: malformed shape"
|
||||
print " error: malformed shape"
|
||||
return None
|
||||
else:
|
||||
if IFCOPENSHELL5 and SEPARATE_PLACEMENTS:
|
||||
|
@ -688,16 +690,16 @@ def getShape(obj,objid):
|
|||
# try to extract a solid shape
|
||||
if sh.Faces:
|
||||
try:
|
||||
if DEBUG: print "Malformed solid. Attempting to fix..."
|
||||
if DEBUG: print " malformed solid. Attempting to fix..."
|
||||
shell = Part.makeShell(sh.Faces)
|
||||
if shell:
|
||||
solid = Part.makeSolid(shell)
|
||||
if solid:
|
||||
sh = solid
|
||||
except:
|
||||
if DEBUG: print "failed to retrieve solid from object ",objid
|
||||
if DEBUG: print " failed to retrieve solid from object ",objid
|
||||
else:
|
||||
if DEBUG: print "object ", objid, " doesn't contain any geometry"
|
||||
if DEBUG: print " object ", objid, " doesn't contain any geometry"
|
||||
if not IFCOPENSHELL5:
|
||||
m = obj.matrix
|
||||
mat = FreeCAD.Matrix(m[0], m[3], m[6], m[9],
|
||||
|
@ -1026,7 +1028,7 @@ def export(exportList,filename):
|
|||
#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 )
|
||||
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 )
|
||||
|
@ -1036,6 +1038,8 @@ def export(exportList,filename):
|
|||
elif otype == "Window":
|
||||
if parent:
|
||||
p = ifc.findByName("IfcWallStandardCase",str(parent.Label))
|
||||
if not p:
|
||||
p = ifc.findByName("IfcWall",str(parent.Label))
|
||||
if not p:
|
||||
p = ifc.findByName("IfcColumn",str(parent.Label))
|
||||
if not p:
|
||||
|
|
Loading…
Reference in New Issue
Block a user