Arch: Adapted IFC, OBJ and DAE exporters to support external color information when running in non-GUI mode
This commit is contained in:
@@ -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]
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user