diff --git a/src/Mod/Arch/ArchIFC.py b/src/Mod/Arch/ArchIFC.py index 2053d85b8a..a64a4f65d2 100644 --- a/src/Mod/Arch/ArchIFC.py +++ b/src/Mod/Arch/ArchIFC.py @@ -41,6 +41,8 @@ def getIfcProduct(IfcType): "Returns an IFC product name from an obj.IfcType" name = "Ifc" + IfcType.replace(" ", "") + if IfcType == "Undefined": + name = "IfcBuildingElementProxy" if name in ArchIFCSchema.IfcProducts: return ArchIFCSchema.IfcProducts[name] diff --git a/src/Mod/Arch/importDAE.py b/src/Mod/Arch/importDAE.py index c3e44d4264..3574c08696 100644 --- a/src/Mod/Arch/importDAE.py +++ b/src/Mod/Arch/importDAE.py @@ -49,7 +49,9 @@ except NameError: pass def checkCollada(): + "checks if collada if available" + global collada COLLADA = None try: @@ -60,8 +62,11 @@ def checkCollada(): else: return True + def triangulate(shape): + "triangulates the given face" + p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") mesher = p.GetInt("ColladaMesher",0) tessellation = p.GetFloat("ColladaTessellation",1.0) @@ -82,7 +87,9 @@ def triangulate(shape): def open(filename): + "called when freecad wants to open a file" + if not checkCollada(): return docname = (os.path.splitext(os.path.basename(filename))[0]).encode("utf8") @@ -92,8 +99,11 @@ def open(filename): read(filename) return doc + def insert(filename,docname): + "called when freecad wants to import a file" + if not checkCollada(): return try: @@ -104,8 +114,11 @@ def insert(filename,docname): read(filename) return doc + def decode(name): + "decodes encoded strings" + try: decodedName = (name.decode("utf8")) except UnicodeDecodeError: @@ -116,7 +129,11 @@ def decode(name): decodedName = name return decodedName + def read(filename): + + "reads a DAE file" + global col col = collada.Collada(filename, ignore=[collada.DaeUnsupportedError]) # Read the unitmeter info from dae file and compute unit to convert to mm @@ -169,8 +186,11 @@ def read(filename): if color and FreeCAD.GuiUp: obj.ViewObject.ShapeColor = color -def export(exportList,filename,tessellation=1): + +def export(exportList,filename,tessellation=1,colors=None): + "called when freecad exports a file" + if not checkCollada(): return p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") scale = p.GetFloat("ColladaScalingFactor",1.0) @@ -261,7 +281,22 @@ def export(exportList,filename,tessellation=1): matref = "ref_"+obj.Material.Name matnode = collada.scene.MaterialNode(matref, mat, inputs=[]) if not matnode: - if FreeCAD.GuiUp: + if colors: + if obj.Name in colors: + color = colors[obj.Name] + if color: + if isinstance(color[0],tuple): + # this is a diffusecolor. For now, use the first color - #TODO: Support per-face colors + color = color[0] + #print("found color for obj",obj.Name,":",color) + kd = color[:3] + effect = collada.material.Effect("effect_"+obj.Name, [], "phong", diffuse=kd, specular=(1,1,1)) + mat = collada.material.Material("mat_"+obj.Name, obj.Name, effect) + colmesh.effects.append(effect) + colmesh.materials.append(mat) + matref = "ref_"+obj.Name + matnode = collada.scene.MaterialNode(matref, mat, inputs=[]) + elif FreeCAD.GuiUp: if hasattr(obj.ViewObject,"ShapeColor"): kd = obj.ViewObject.ShapeColor[:3] effect = collada.material.Effect("effect_"+obj.Name, [], "phong", diffuse=kd, specular=(1,1,1)) diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 010410bdb7..8017494b31 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -1462,7 +1462,9 @@ class recycler: # ************************************************************************************************ # ********** export IFC **************** -def export(exportList,filename): + + +def export(exportList,filename,colors=None): "exports FreeCAD contents to an IFC file" @@ -1671,7 +1673,7 @@ def export(exportList,filename): # getting the representation - representation,placement,shapetype = getRepresentation(ifcfile,context,obj,forcebrep=(brepflag or FORCE_BREP)) + representation,placement,shapetype = getRepresentation(ifcfile,context,obj,forcebrep=(brepflag or FORCE_BREP),colors=colors) if getstd: if isStandardCase(obj,ifctype): ifctype += "StandardCase" @@ -1713,7 +1715,7 @@ def export(exportList,filename): if hasattr(obj,"Additions") and (shapetype in ["extrusion","no shape"]): for o in obj.Additions: - r2,p2,c2 = getRepresentation(ifcfile,context,o) + r2,p2,c2 = getRepresentation(ifcfile,context,o,colors=colors) if DEBUG: print(" adding ",c2," : ",o.Label) l = o.Label if six.PY2: @@ -1750,7 +1752,7 @@ def export(exportList,filename): guests.append(o) if hasattr(obj,"Subtractions") and (shapetype in ["extrusion","no shape"]): for o in obj.Subtractions + guests: - r2,p2,c2 = getRepresentation(ifcfile,context,o,subtraction=True) + r2,p2,c2 = getRepresentation(ifcfile,context,o,subtraction=True,colors=colors) if DEBUG: print(" subtracting ",c2," : ",o.Label) l = o.Label if six.PY2: @@ -2597,34 +2599,112 @@ def export(exportList,filename): remaining = [anno for anno in annos.values() if anno not in swallowed] if remaining: if not defaulthost: - defaulthost = ifcfile.createIfcBuildingStorey( + if ADD_DEFAULT_STOREY: + defaulthost = ifcfile.createIfcBuildingStorey( + ifcopenshell.guid.new(), + history, + "Default Storey", + '', + None, + None, + None, + None, + "ELEMENT", + None + ) + # if ADD_DEFAULT_STOREY is on, we need a building to host it, regardless of ADD_DEFAULT_BUILDING + if not buildings: + buildings = [ifcfile.createIfcBuilding( + ifcopenshell.guid.new(), + history, + "Default Building", + '', + None, + None, + None, + None, + "ELEMENT", + None, + None, + None + )] + if sites: + ifcfile.createIfcRelAggregates( + ifcopenshell.guid.new(), + history, + 'SiteLink', + '', + sites[0], + buildings + ) + else: + ifcfile.createIfcRelAggregates( + ifcopenshell.guid.new(), + history, + 'ProjectLink', + '', + project,buildings + ) + ifcfile.createIfcRelAggregates( + ifcopenshell.guid.new(), + history, + 'DefaultStoreyLink', + '', + buildings[0], + [defaulthost] + ) + elif ADD_DEFAULT_BUILDING: + if not buildings: + defaulthost = ifcfile.createIfcBuilding( + ifcopenshell.guid.new(), + history, + "Default Building", + '', + None, + None, + None, + None, + "ELEMENT", + None, + None, + None + ) + if sites: + ifcfile.createIfcRelAggregates( + ifcopenshell.guid.new(), + history, + 'SiteLink', + '', + sites[0], + [defaulthost] + ) + else: + ifcfile.createIfcRelAggregates( + ifcopenshell.guid.new(), + history, + 'ProjectLink', + '', + project, + [defaulthost] + ) + if defaulthost: + ifcfile.createIfcRelContainedInSpatialStructure( ifcopenshell.guid.new(), history, - "Default Storey", + 'AnnotationsLink', '', - None, - None, - None, - None, - "ELEMENT", - None + remaining, + defaulthost ) + else: ifcfile.createIfcRelAggregates( ifcopenshell.guid.new(), history, - 'DefaultStoreyLink', + 'ProjectLink', '', - buildings[0], - [defaulthost] + project, + remaining ) - ifcfile.createIfcRelContainedInSpatialStructure( - ifcopenshell.guid.new(), - history, - 'AnnotationsLink', - '', - remaining, - defaulthost - ) if DEBUG: print("writing ",filename,"...") @@ -2648,6 +2728,8 @@ def export(exportList,filename): # ************************************************************************************************ # ********** helper for export IFC ************** + + def isStandardCase(obj,ifctype): if ifctype.endswith("StandardCase"): @@ -2997,7 +3079,7 @@ def getProfile(ifcfile,p): return profile -def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1): +def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1,colors=None): """returns an IfcShapeRepresentation object or None""" @@ -3292,20 +3374,36 @@ def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tess solidType = "MappedRepresentation" # set surface style - if FreeCAD.GuiUp and (not subtraction) and hasattr(obj.ViewObject,"ShapeColor"): + shapecolor = None + diffusecolor = None + transparency = 0.0 + if colors: + # color dict is given + if obj.Name in colors: + color = colors[obj.Name] + shapecolor = color + if isinstance(color[0],tuple): + # this is a diffusecolor. For now, use the first color - #TODO: Support per-face colors + diffusecolor = color + shapecolor = color[0] + elif FreeCAD.GuiUp and (not subtraction) and hasattr(obj.ViewObject,"ShapeColor"): # every object gets a surface style. If the obj has a material, the surfstyle # is named after it. Revit will treat surfacestyles as materials (and discard # actual ifcmaterial) + shapecolor = obj.ViewObject.ShapeColor[:3] + transparency = obj.ViewObject.Transparency/100.0 + if hasattr(obj.ViewObject,"DiffuseColor"): + diffusecolor = obj.ViewObject.DiffuseColor + if shapecolor: key = None - rgbt = [obj.ViewObject.ShapeColor[:3]+(obj.ViewObject.Transparency/100.0,) for shape in shapes] - if hasattr(obj.ViewObject,"DiffuseColor") \ - and obj.ViewObject.DiffuseColor \ - and (len(obj.ViewObject.DiffuseColor) == len(obj.Shape.Faces)) \ + rgbt = [shapecolor+(transparency,) for shape in shapes] + if diffusecolor \ + and (len(diffusecolor) == len(obj.Shape.Faces)) \ and (len(obj.Shape.Solids) == len(shapes)): i = 0 rgbt = [] for sol in obj.Shape.Solids: - rgbt.append(obj.ViewObject.DiffuseColor[i]) + rgbt.append(diffusecolor[i]) i += len(sol.Faces) for i,shape in enumerate(shapes): key = rgbt[i] diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index d217dc7de8..5aaef03621 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -118,8 +118,16 @@ def getIndices(shape,offset): flist.append(fi) return vlist,elist,flist -def export(exportList,filename): - "called when freecad exports a file" + +def export(exportList,filename,colors=None): + + """export(exportList,filename,colors=None): + Called when freecad exports a file. exportList is a list + of objects, filename is the .obj file to export (a .mtl + file with same name will also be created together), and + optionally colors can be a dict containing ["objectName:colorTuple"] + pairs for use in non-GUI mode.""" + import codecs outfile = codecs.open(filename,"wb",encoding="utf8") ver = FreeCAD.Version() @@ -132,7 +140,7 @@ def export(exportList,filename): materials = [] outfile.write("mtllib " + os.path.basename(filenamemtl) + "\n") for obj in objectslist: - if obj.isDerivedFrom("Part::Feature"): + if obj.isDerivedFrom("Part::Feature") or obj.isDerivedFrom("Mesh::Feature"): hires = None if FreeCAD.GuiUp: visible = obj.ViewObject.isVisible() @@ -163,7 +171,10 @@ def export(exportList,filename): if hires: vlist,elist,flist = getIndices(hires,offset) else: - vlist,elist,flist = getIndices(obj.Shape,offset) + if hasattr(obj,"Shape") and obj.Shape: + vlist,elist,flist = getIndices(obj.Shape,offset) + elif hasattr(obj,"Mesh") and obj.Mesh: + vlist,elist,flist = getIndices(obj.Mesh,offset) if vlist == None: FreeCAD.Console.PrintError("Unable to export object "+obj.Label+". Skipping.\n") else: @@ -179,9 +190,20 @@ def export(exportList,filename): materials.append(obj.Material) m = True if not m: - if FreeCAD.GuiUp: + if colors: + if obj.Name in colors: + color = colors[obj.Name] + if color: + if isinstance(color[0],tuple): + # this is a diffusecolor. For now, use the first color - #TODO: Support per-face colors + color = color[0] + #print("found color for obj",obj.Name,":",color) + mn = Draft.getrgb(color,testbw=False)[1:] + outfile.write("usemtl color_" + mn + "\n") + materials.append(("color_" + mn,color,0)) + elif FreeCAD.GuiUp: if hasattr(obj.ViewObject,"ShapeColor") and hasattr(obj.ViewObject,"Transparency"): - mn = Draft.getrgb(obj.ViewObject.ShapeColor)[1:] + mn = Draft.getrgb(obj.ViewObject.ShapeColor,testbw=False)[1:] outfile.write("usemtl color_" + mn + "\n") materials.append(("color_" + mn,obj.ViewObject.ShapeColor,obj.ViewObject.Transparency))