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:
Gaël Écorchard
2025-06-24 11:02:08 +02:00
parent 9a039860a3
commit 346c7581d4

View File

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