# *************************************************************************** # * Copyright (c) 2023 David Carter * # * * # * This file is part of FreeCAD. * # * * # * FreeCAD is free software: you can redistribute it and/or modify it * # * under the terms of the GNU Lesser General Public License as * # * published by the Free Software Foundation, either version 2.1 of the * # * License, or (at your option) any later version. * # * * # * FreeCAD is distributed in the hope that it will be useful, but * # * WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * # * Lesser General Public License for more details. * # * * # * You should have received a copy of the GNU Lesser General Public * # * License along with FreeCAD. If not, see * # * . * # * * # **************************************************************************/ __title__ = "material model utilities" __author__ = "David Carter" __url__ = "https://www.freecad.org" import os import io from pathlib import Path import yaml import FreeCAD unicode = str __models = {} __modelsByPath = {} def _dereference(parent, child): # Add the child parameters to the parent parentModel = parent["model"] parentBase = parent["base"] childModel = child["model"] childBase = child["base"] for name, value in childModel[childBase].items(): if name not in ["Name", "UUID", "URL", "Description", "DOI", "Inherits"] and \ name not in parentModel[parentBase]: # Don't add if it's already there parentModel[parentBase][name] = value print("dereferenced:") print(parentModel) def _dereferenceInheritance(data): if not data["dereferenced"]: data["dereferenced"] = True # Prevent recursion loops model = data["model"] base = data["base"] if "Inherits" in model[base]: print("Model '{0}' inherits from:".format(data["name"])) for parent in model[base]["Inherits"]: print("\t'{0}'".format(parent)) print("\t\t'{0}'".format(parent.keys())) print("\t\t'{0}'".format(parent["UUID"])) # This requires that all models have already been loaded undereferenced child = __models[parent["UUID"]] if child is not None: _dereference(data, child) def _dereferenceAll(): for data in __models.values(): _dereferenceInheritance(data) def _scanFolder(folder): print("Scanning folder '{0}'".format(folder.absolute())) for child in folder.iterdir(): if child.is_dir(): _scanFolder(child) else: if child.suffix.lower() == ".yml": data = getModelFromPath(child) if data is not None: __models[data["uuid"]] = data __modelsByPath[data["path"]] = data # print(data["model"]) else: print("Extension '{0}'".format(child.suffix.lower())) def _scanModels(libraries): __models = {} # Clear the current library __modelsByPath = {} print("_scanModels") print(libraries) for library in libraries: _scanFolder(Path(library)) # Satisfy aany inheritances _dereferenceAll() def getPreferredSaveDirectory(): pass def getModelLibraries(): libraries = [] # TODO: Expand beyond the standard models as we do for material paths path = Path(FreeCAD.getResourceDir()) / "Mod/Material/Resources/Models" libraries.append(path) _scanModels(libraries) return libraries def getModel(uuid): """ Retrieve the specified model. """ if len(__models) < 1: getModelLibraries() if uuid not in __models: return None return __models[uuid] def getModelFromPath(filePath): """ Retrieve the model at the specified path. This may not need public exposure? """ try: path = Path(filePath) stream = open(path.absolute(), "r") model = yaml.safe_load(stream) base = "Model" if "AppearanceModel" in model: base = "AppearanceModel" uuid = model[base]["UUID"] name = model[base]["Name"] data = {} data["base"] = base data["name"] = name data["path"] = path.absolute() data["uuid"] = uuid data["model"] = model data["dereferenced"] = False return data except Exception as ex: print("Unable to load '{0}'".format(path.absolute())) print(ex) return None def saveModel(model, path): """ Write the model to the specified path """