BIM: fix geometry under node tags
I took the file
[link_3.dae](514790a553/kuka_kr210_support/meshes/kr210l150/visual/link_3.dae)
as test.
Before this commit, no geometry is loaded because the childer of `node`
are `Node` instances not geometry.
To access all the geometries, `col.scene.objects("geometry")` is used,
cf. https://pycollada.readthedocs.io/en/latest/structure.html.
Signed-off-by: Gaël Écorchard <gael@km-robotics.cz>
This commit is contained in:
@@ -133,49 +133,83 @@ def insert(filename, docname):
|
|||||||
|
|
||||||
def read(filename):
|
def read(filename):
|
||||||
"""Read a DAE file."""
|
"""Read a DAE file."""
|
||||||
|
doc = FreeCAD.activeDocument()
|
||||||
|
if not doc:
|
||||||
|
return
|
||||||
col = collada.Collada(filename, ignore=[collada.common.DaeUnsupportedError])
|
col = collada.Collada(filename, ignore=[collada.common.DaeUnsupportedError])
|
||||||
# Read the unitmeter info from DAE file and compute unit to convert to mm.
|
# Read the unitmeter info from DAE file and compute unit to convert to mm.
|
||||||
unitmeter = col.assetInfo.unitmeter or 1.0
|
unit_meter = col.assetInfo.unitmeter or 1.0
|
||||||
unit = unitmeter / 0.001
|
unit = unit_meter / 0.001
|
||||||
# for geom in col.geometries:
|
bound_geom: collada.geometry.BoundGeometry
|
||||||
# for geom in col.scene.objects("geometry"):
|
# Implementation note: there's also `col.geometries` but when using them,
|
||||||
for node in col.scene.nodes:
|
# the materials are string and Gaël didn't find a way to get the material
|
||||||
for child in node.children:
|
# node from this string.
|
||||||
if not isinstance(child, collada.scene.GeometryNode):
|
for bound_geom in col.scene.objects('geometry'):
|
||||||
|
prim: collada.primitive.BoundPrimitive
|
||||||
|
for prim in bound_geom.primitives():
|
||||||
|
if not isinstance(prim, collada.triangleset.BoundTriangleSet):
|
||||||
|
# e.g. a BoundLineSet, which is not supported yet.
|
||||||
continue
|
continue
|
||||||
geom: collada.scenes.GeometryNode = child.geometry
|
# Get the materials and associated vertices.
|
||||||
mat_symbols: list[str] = [m.symbol for m in child.materials]
|
meshes: dict[collada.scene.MaterialNode, list] = {}
|
||||||
for prim in geom.primitives:
|
tri: collada.triangleset.Triangle
|
||||||
meshdata = []
|
for tri in prim:
|
||||||
for tri in prim:
|
material_node: collada.material.Material = tri.material
|
||||||
# tri.vertices is a numpy array.
|
if material_node not in meshes:
|
||||||
meshdata.append((tri.vertices * unit).tolist())
|
# Not yet in the dict, create a new entry.
|
||||||
mesh = Mesh.Mesh(meshdata)
|
meshes[material_node] = []
|
||||||
try:
|
if len(tri.vertices) != 3:
|
||||||
name = geom.name
|
msg = (
|
||||||
except AttributeError:
|
f"Warning: triangle with {len(tri.vertices)} vertices found"
|
||||||
name = geom.id
|
f" in {bound_geom.original.name}, expected 3. Skipping this triangle."
|
||||||
obj = FreeCAD.ActiveDocument.addObject("Mesh::Feature", name)
|
)
|
||||||
|
FreeCAD.Console.PrintWarning(msg + "\n")
|
||||||
|
continue
|
||||||
|
# tri.vertices is a numpy array.
|
||||||
|
meshes[material_node].append((tri.vertices * unit).tolist())
|
||||||
|
# Create a mesh for each material node.
|
||||||
|
for material_node, vertices in meshes.items():
|
||||||
|
mesh = Mesh.Mesh(vertices)
|
||||||
|
name = bound_geom.original.name
|
||||||
|
if not name:
|
||||||
|
name = bound_geom.original.id
|
||||||
|
obj = doc.addObject("Mesh::Feature", name)
|
||||||
obj.Label = name
|
obj.Label = name
|
||||||
obj.Mesh = mesh
|
obj.Mesh = mesh
|
||||||
|
if not material_node:
|
||||||
|
continue
|
||||||
if FreeCAD.GuiUp:
|
if FreeCAD.GuiUp:
|
||||||
try:
|
fc_mat = FreeCAD.Material()
|
||||||
mat_index = mat_symbols.index(prim.material)
|
# We do not import transparency because it is often set
|
||||||
material = child.materials[mat_index].target
|
# wrongly (transparency mistaken for opacity).
|
||||||
color = material.effect.diffuse
|
# TODO: Ask whether to import transparency.
|
||||||
obj.ViewObject.ShapeColor = color
|
field_map = {
|
||||||
except ValueError:
|
"ambient": "AmbientColor",
|
||||||
# Material not found.
|
"diffuse": "DiffuseColor",
|
||||||
pass
|
"emission": "EmissiveColor",
|
||||||
except TypeError:
|
"specular": "SpecularColor",
|
||||||
# color is not a tuple but a texture.
|
"shininess": "Shininess",
|
||||||
pass
|
# "transparency": "Transparency",
|
||||||
|
}
|
||||||
|
for col_field, fc_field in field_map.items():
|
||||||
|
try:
|
||||||
|
# Implementation note: using floats, so values must
|
||||||
|
# be within [0, 1]. OK.
|
||||||
|
setattr(fc_mat, fc_field, getattr(material_node.effect, col_field))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
# color is not a tuple but a texture.
|
||||||
|
pass
|
||||||
|
obj.ViewObject.ShapeAppearance = (fc_mat,)
|
||||||
|
|
||||||
# Print the errors that occurred during reading.
|
# Print the errors that occurred during reading.
|
||||||
if col.errors:
|
if col.errors:
|
||||||
FreeCAD.Console.PrintWarning(translate("BIM", "File was read but some errors occurred:") + "\n")
|
FreeCAD.Console.PrintWarning(translate("BIM", "File was read but some errors occurred:") + "\n")
|
||||||
for e in col.errors:
|
for e in col.errors:
|
||||||
FreeCAD.Console.PrintWarning(str(e) + "\n")
|
FreeCAD.Console.PrintWarning(str(e) + "\n")
|
||||||
|
if FreeCAD.GuiUp:
|
||||||
|
FreeCAD.Gui.SendMsgToActiveView("ViewFit")
|
||||||
|
|
||||||
|
|
||||||
def export(
|
def export(
|
||||||
|
|||||||
Reference in New Issue
Block a user