Arch: Adapted IFC, OBJ and DAE exporters to support external color information when running in non-GUI mode

This commit is contained in:
Yorik van Havre
2019-06-12 19:28:43 -03:00
parent a3a35d12b4
commit 4fd42d02b6
4 changed files with 195 additions and 38 deletions

View File

@@ -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]

View File

@@ -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))

View File

@@ -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]

View File

@@ -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))