Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arch: Fix multiple issues with ImportOBJ.py #10989

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
280 changes: 144 additions & 136 deletions src/Mod/Arch/importOBJ.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#***************************************************************************

Check warning on line 1 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

would reformat src/Mod/Arch/importOBJ.py
#* Copyright (c) 2011 Yorik van Havre <yorik@uncreated.net> *
#* *
#* This program is free software; you can redistribute it and/or modify *
Expand Down Expand Up @@ -51,7 +51,7 @@

p = Draft.precision()

if open.__module__ in ['__builtin__','io']:

Check failure on line 54 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Using variable 'open' before assignment (used-before-assignment)
pythonopen = open

def findVert(aVertex,aList):
Expand All @@ -69,84 +69,68 @@
vnlist = []
elist = []
flist = []
curves = None
hascurve = False
mesh = None

if isinstance(shape,Part.Shape):
for e in shape.Edges:
try:
if not isinstance(e.Curve,Part.LineSegment):
if not curves:
if obj.isDerivedFrom("App::Link"):
myshape = obj.LinkedObject.Shape.copy(False)
myshape.Placement=obj.LinkPlacement
else:
myshape = obj.Shape.copy(False)
myshape.Placement = obj.getGlobalPlacement()
mesh = MeshPart.meshFromShape(Shape=myshape, LinearDeflection=0.1, AngularDeflection=0.7, Relative=True)
FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")
break
if not isinstance(e.Curve,Part.Line):
hascurve = True
except Exception: # unimplemented curve type
if obj.isDerivedFrom("App::Link"):
if obj.Shape:
myshape = obj.Shape.copy(False)
myshape.Placement=obj.LinkPlacement
else:
myshape = obj.Shape.copy(False)
myshape.Placement=obj.getGlobalPlacement()
mesh = MeshPart.meshFromShape(Shape=myshape, LinearDeflection=0.1, AngularDeflection=0.7, Relative=True)
FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")
break
hascurve = True
if hascurve:
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Mesh")
tol = param.GetFloat("MaxDeviationExport",0.1)
mesh = Mesh.Mesh()
mesh.addFacets(shape.getFaces(tol))
FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")

Check warning on line 87 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (117/100) (line-too-long)
break
elif isinstance(shape,Mesh.Mesh):
mesh = shape
curves = shape.Topology

if mesh:
for v in mesh.Topology[0]:
vlist.append(" "+str(round(v[0],p))+" "+str(round(v[1],p))+" "+str(round(v[2],p)))

for vn in mesh.Facets:
vnlist.append(" "+str(vn.Normal[0]) + " " + str(vn.Normal[1]) + " " + str(vn.Normal[2]))
vnlist.append(" "+str(round(vn.Normal[0],p))+" "+str(round(vn.Normal[1],p))+" "+str(round(vn.Normal[2],p)))

Check warning on line 97 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (119/100) (line-too-long)

for i, vn in enumerate(mesh.Topology[1]):
flist.append(" "+str(vn[0]+offsetv)+"//"+str(i+offsetvn)+" "+str(vn[1]+offsetv)+"//"+str(i+offsetvn)+" "+str(vn[2]+offsetv)+"//"+str(i+offsetvn)+" ")

Check warning on line 100 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (161/100) (line-too-long)
else:
if curves:
for v in curves[0]:
vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p)))
for f in curves[1]:
fi = ""
for vi in f:
fi += " " + str(vi + offsetv)
flist.append(fi)
else:
for v in shape.Vertexes:
vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
if not shape.Faces:
for e in shape.Edges:
if DraftGeomUtils.geomType(e) == "Line":
ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offsetv)
ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offsetv)
elist.append(ei)
for f in shape.Faces:
if len(f.Wires) > 1:
# if we have holes, we triangulate
tris = f.tessellate(1)
for fdata in tris[1]:
fi = ""
for vi in fdata:
vdata = Part.Vertex(tris[0][vi])
fi += " " + str(findVert(vdata,shape.Vertexes) + offsetv)
flist.append(fi)
else:
for v in shape.Vertexes:
vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
if not shape.Faces:
for e in shape.Edges:
if DraftGeomUtils.geomType(e) == "Line":
ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offsetv)
ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offsetv)
elist.append(ei)
for f in shape.Faces:
if len(f.Wires) > 1:
# if we have holes, we triangulate
tris = f.tessellate(1)
for fdata in tris[1]:
fi = ""
for e in f.OuterWire.OrderedEdges:
#print(e.Vertexes[0].Point,e.Vertexes[1].Point)
v = e.Vertexes[0]
ind = findVert(v,shape.Vertexes)
if ind is None:
return None,None,None
fi += " " + str(ind + offsetv)
for vi in fdata:
vdata = Part.Vertex(tris[0][vi])
fi += " " + str(findVert(vdata,shape.Vertexes) + offsetv)
flist.append(fi)
else:
fi = ""
edges = f.OuterWire.OrderedEdges
# Avoid flipped normals:
if f.Orientation == "Reversed":
edges.reverse()
for e in edges:
v = e.Vertexes[0 if e.Orientation == "Forward" else 1]
ind = findVert(v,shape.Vertexes)
if ind is None:
return None,None,None,None
fi += " " + str(ind + offsetv)
flist.append(fi)

return vlist,vnlist,elist,flist


Expand All @@ -171,97 +155,121 @@
filenamemtl = filename[:-4] + ".mtl"
materials = []
outfile.write("mtllib " + os.path.basename(filenamemtl) + "\n")

for obj in objectslist:
if obj.isDerivedFrom("Part::Feature") or obj.isDerivedFrom("Mesh::Feature") or obj.isDerivedFrom("App::Link"):
hires = None
if FreeCAD.GuiUp:
visible = obj.ViewObject.isVisible()
if obj.ViewObject.DisplayMode == "HiRes":
# check if high-resolution object is available
if hasattr(obj,"HiRes"):
if obj.HiRes:
if obj.HiRes.isDerivedFrom("Mesh::Feature"):
m = obj.HiRes.Mesh
else:
m = obj.HiRes.Shape
hires = m.copy()
hires.Placement = obj.Placement.multiply(m.Placement)
if not hires:
if hasattr(obj,"CloneOf"):
if obj.CloneOf:
if hasattr(obj.CloneOf,"HiRes"):
if obj.CloneOf.HiRes:
if obj.CloneOf.HiRes.isDerivedFrom("Mesh::Feature"):
m = obj.CloneOf.HiRes.Mesh
else:
m = obj.CloneOf.HiRes.Shape
hires = m.copy()
hires.Placement = obj.Placement.multiply(obj.CloneOf.Placement).multiply(m.Placement)
else:
visible = True
if visible:
if hires:
vlist,vnlist,elist,flist = getIndices(obj,hires,offsetv,offsetvn)
else:
if hasattr(obj,"Shape") and obj.Shape:
vlist,vnlist,elist,flist = getIndices(obj,obj.Shape,offsetv,offsetvn)
elif hasattr(obj,"Mesh") and obj.Mesh:
vlist,vnlist, elist,flist = getIndices(obj,obj.Mesh,offsetv,offsetvn)
if vlist is None:
FreeCAD.Console.PrintError("Unable to export object "+obj.Label+". Skipping.\n")
else:
offsetv += len(vlist)
offsetvn += len(vnlist)
outfile.write("o " + obj.Label + "\n")

# write material
m = False
if hasattr(obj,"Material"):
if obj.Material:
if hasattr(obj.Material,"Material"):
outfile.write("usemtl " + obj.Material.Name + "\n")
materials.append(obj.Material)
m = True
if not m:
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,testbw=False)[1:]
outfile.write("usemtl color_" + mn + "\n")
materials.append(("color_" + mn,obj.ViewObject.ShapeColor,obj.ViewObject.Transparency))

# write geometry
for v in vlist:
outfile.write("v" + v + "\n")
for vn in vnlist:
outfile.write("vn" + vn + "\n")
for e in elist:
outfile.write("l" + e + "\n")
for f in flist:
outfile.write("f" + f + "\n")
if FreeCAD.GuiUp:
visible = obj.Visibility
else:
visible = True
if not visible:
continue

if not (obj.isDerivedFrom("Part::Feature")
or obj.isDerivedFrom("Mesh::Feature")
or obj.isDerivedFrom("App::Link")):
continue

if obj.isDerivedFrom("App::Link"):
# Get global placement from a Link:
obj_place = obj.Placement
parents = obj.Parents
if parents:
doc = obj.Document
parents = [parents[0][0]] + [doc.getObject(name) for name in parents[0][1].split(".")[:-2]]

Check warning on line 178 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (107/100) (line-too-long)
parents.reverse() # child-parent-grandparent order.
for parent in parents:
obj_place = parent.Placement.multiply(obj_place)
else:
obj_place = obj.getGlobalPlacement()

hires = None
if FreeCAD.GuiUp:
if obj.ViewObject.DisplayMode == "HiRes":
# check if high-resolution object is available
if hasattr(obj,"HiRes") and obj.HiRes:
if obj.HiRes.isDerivedFrom("Mesh::Feature"):
hires = obj.HiRes.Mesh.copy()
else:
hires = obj.HiRes.Shape.copy(False, True)
hires.Placement = obj_place.multiply(hires.Placement)
if not hires \
and hasattr(obj,"CloneOf") \
and obj.CloneOf \
and hasattr(obj.CloneOf,"HiRes") \
and obj.CloneOf.HiRes:
if obj.CloneOf.HiRes.isDerivedFrom("Mesh::Feature"):
hires = obj.CloneOf.HiRes.Mesh.copy()
else:
hires = obj.CloneOf.HiRes.Shape.copy(False, True)
hires.Placement = obj_place.multiply(obj.CloneOf.Placement).multiply(hires.Placement)

Check warning on line 204 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (105/100) (line-too-long)

if hires:
vlist,vnlist,elist,flist = getIndices(obj,hires,offsetv,offsetvn)
elif hasattr(obj,"Shape") and obj.Shape:
shape = obj.Shape.copy(False, True)
shape.Placement = obj_place
vlist,vnlist,elist,flist = getIndices(obj,shape,offsetv,offsetvn)
elif hasattr(obj,"Mesh") and obj.Mesh:
mesh = obj.Mesh.copy()
mesh.Placement = obj_place
vlist,vnlist, elist,flist = getIndices(obj,mesh,offsetv,offsetvn)

if vlist is None:
FreeCAD.Console.PrintError("Unable to export object "+obj.Label+". Skipping.\n")
else:
offsetv += len(vlist)
offsetvn += len(vnlist)
outfile.write("o " + obj.Label + "\n")

# write material
m = False
if hasattr(obj,"Material"):
if obj.Material:
if hasattr(obj.Material,"Material"):
outfile.write("usemtl " + obj.Material.Name + "\n")
materials.append(obj.Material)
m = True
if not m:
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

Check warning on line 238 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (119/100) (line-too-long)
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"):

Check warning on line 245 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (103/100) (line-too-long)
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))

Check warning on line 248 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (111/100) (line-too-long)

# write geometry
for v in vlist:
outfile.write("v" + v + "\n")
for vn in vnlist:
outfile.write("vn" + vn + "\n")
for e in elist:
outfile.write("l" + e + "\n")
for f in flist:
outfile.write("f" + f + "\n")

outfile.close()
FreeCAD.Console.PrintMessage(translate("Arch","Successfully written") + " " + filename + "\n")
if materials:
outfile = pythonopen(filenamemtl,"w")

Check failure on line 263 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Using variable 'pythonopen' before assignment (used-before-assignment)
outfile.write("# FreeCAD v" + ver[0] + "." + ver[1] + " build" + ver[2] + " Arch module\n")
outfile.write("# https://www.freecad.org\n")
kinds = {"AmbientColor":"Ka ","DiffuseColor":"Kd ","SpecularColor":"Ks ","EmissiveColor":"Ke ","Transparency":"Tr ","Dissolve":"d "}

Check warning on line 266 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (140/100) (line-too-long)
done = [] # store names to avoid duplicates
for mat in materials:
if isinstance(mat,tuple):
if not mat[0] in done:
outfile.write("newmtl " + mat[0] + "\n")
outfile.write("Kd " + str(mat[1][0]) + " " + str(mat[1][1]) + " " + str(mat[1][2]) + "\n")

Check warning on line 272 in src/Mod/Arch/importOBJ.py

View workflow job for this annotation

GitHub Actions / Lint / Lint

Line too long (110/100) (line-too-long)
outfile.write("Tr " + str(mat[2]/100) + "\n")
outfile.write("d " + str(1-mat[2]/100) + "\n")
done.append(mat[0])
Expand Down