With KiCad 6, is there any way to get a report on missing 3D models for a design?
Can we run a report from the PCB (like a BOM) that lists all the parts and STEP models? (We do something similar in the schematic to find missing footprint fields)
With KiCad 6, is there any way to get a report on missing 3D models for a design?
Can we run a report from the PCB (like a BOM) that lists all the parts and STEP models? (We do something similar in the schematic to find missing footprint fields)
If there was such a thing, I would expect it to be in:
Pcb Editor / File / Board Setup / Design Rules / Violation Severity / Miscellaneous
A possible snatch is that it’s common to add links to 3D symbols in the footprint to non existing 3D models. The idea is that 3D models can be added by just copying them to the right directory and without having to update the footprints themselves.
If it doesn’t already exist, this feature might be something that could be done in a python plugin. I don’t know the API, but I imagine it would be easy enough to cycle through all the footprints and capture the defined 3D file(s) taking note of which footprints don’t have file names specified. Then cycle through the list of collected 3D filenames and see if they can be found in the computer’s filesystem taking note of ones that can’t be found. Then generate a report based on what wasn’t found. The script should be able to handle footprints that have multiple 3D filenames.
I’m just thinking through the theory of operation, not volunteering to write any lines of code.
We have a script that does it on a library level. This could be a starting point. https://gitlab.com/kicad/libraries/kicad-library-utils/-/blob/master/klc-check/check_3d_coverage.py
I have however not run this in ages so i have no idea if it still works.
Interesting, I would use this
Her you go guys. The script needs a couple of changes, but it works for my projects on 5.1.x interpreter. Might still contain bugs though.
import pcbnew
import os.path
board = pcbnew.LoadBoard('archived_test_project/archive_test_project.kicad_pcb')
# if running standalone (outside of pcbnew)
if os.getenv("KISYS3DMOD") is None:
os.environ["KISYS3DMOD"] = os.path.normpath("D://Mitja//Plate//Kicad_libs//official_libs//Packages3D")
if os.getenv("KIPRJMOD") is None:
os.environ["KIPRJMOD"] = os.path.abspath(os.path.dirname(board.GetFileName()))
# prepare folder for 3Dmodels
proj_path = os.path.dirname(os.path.abspath(board.GetFileName()))
# get all footprints
footprints = board.GetModules()
fp_without_models = []
# go through all the footprints
for fp in footprints:
fp_ref = fp.GetReference()
# for each footprint get all 3D models
fp_models = fp.Models()
# for each 3D model find it's path
for model in fp_models:
model_path = model.m_Filename
# check if path is encoded with variables
if "${" in model_path or "$(" in model_path:
# get environment variable name
start_index = model_path.find("${") + 2 or model_path.find("$(") + 2
end_index = model_path.find("}") or model_path.find(")")
env_var = model_path[start_index:end_index]
# check if variable is defined
path = os.getenv(env_var)
# if variable is defined, get absolute path
if path is not None:
clean_model_path = os.path.normpath(path + model_path[end_index + 1:])
# if variable is not defined, we can not find the model. Thus don't put it on the list
else:
print("Can not find model defined with enviroment variable:\n" + model_path)
fp_without_models.append((fp_ref, model_path))
continue
# check if path is absolute or relative
elif model_path == os.path.basename(model_path):
clean_model_path = os.path.normpath(proj_path + "//" + model_path)
# check if model is given with absolute path
elif os.path.exists(model_path):
clean_model_path = model_path
# otherwise we don't know how to parse the path
else:
print("Ambiguios path for the model: " + model_path)
# test default 3D_library location "KISYS3DMOD"
if os.path.exists(os.path.normpath(os.path.join(os.getenv("KISYS3DMOD"), model_path))):
clean_model_path = os.path.normpath(os.path.join(os.getenv("KISYS3DMOD"), model_path))
print("Going with: " + clean_model_path)
# test in project folder location
elif os.path.exists(os.path.normpath(os.path.join(proj_path, model_path))):
clean_model_path = os.path.normpath(os.path.join(proj_path, model_path))
print("Going with: " + clean_model_path)
else:
print("Can not find model defined with path:\n" + model_path)
fp_without_models.append((fp_ref, model_path))
clean_model_path = None
continue
model_path_without_extension = clean_model_path.rsplit('.', 1)[0]
found_at_least_one = False
if clean_model_path:
model_without_extension = clean_model_path.rsplit('.', 1)[0]
for ext in ['.stp', '.step']:
if os.path.exists(model_without_extension + ext):
found_at_least_one = True
if not found_at_least_one:
fp_without_models.append((fp.GetReference(), clean_model_path))
pass
pass
print(repr(fp_without_models))
put it on github, please
I am tempted to wrap this around a wxpython GUI and finish it as an action plugin, but I cannot even find the time to support my current plugins, so I’d prefer is somebody else takes the torch with this plugin. And also with V6 around the corner I don’t see a sense to develop a plugin that I’ll have to port to V6.
So at the moment this will (sadly) stay as it is. Thanks for understanding
At least upload it somewhere and I suggest that you declare a suitable license if you want others to take it up
Hi @MitjaN
for the moment I’ve added your code to my tools…
easyw/kicad-action-tools/checking3Dmodels
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.