Material: Material handling enhancements

Rework of the material handling system.

This first part concntrates on a rework of the material cards.
Rather than use a fixed list of possible properties, properties can
be defined separately in their own files and mixed to provide a
complete list of possible properties. Properties can be inherited.

The cards then provide values for the properties. These can also
be inherited allowing for small changes in cards as required.

The new property definitions are more extensive than previously.
2 and 3 dimensional arrays of properties can be defined. Values
are obtained by calling an API instead of reading from a dictionary.

For compatibility, a Python dictionary of values can be obtained
similar to how it was done previously, but this is considered a
deprecated API and won't support the newer advanced features.

The editor is completely reworked. It will be able to edit older format
material cards, but can only save them in the new format.

For testing during the development phase, a system preference can
specifiy wether the old or new material editors are to be used. This
option will be removed before release.
This commit is contained in:
David Carter
2023-09-14 22:52:48 -04:00
parent 563dc0b0cc
commit 6624fa3775
397 changed files with 19222 additions and 4312 deletions

View File

@@ -0,0 +1,76 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License (LGPL) *
* as published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* for detail see the LICENCE text file. *
* *
* 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 Library General Public *
* License along with FreeCAD; if not, write to the Free Software *
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
* USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <Base/Console.h>
#include <Base/Interpreter.h>
#include <Base/PyObjectBase.h>
// #include "Model.h"
#include "MaterialManagerPy.h"
#include "MaterialPy.h"
#include "ModelManagerPy.h"
#include "ModelPropertyPy.h"
#include "ModelPy.h"
namespace Materials
{
class Module: public Py::ExtensionModule<Module>
{
public:
Module()
: Py::ExtensionModule<Module>("Material")
{
initialize("This module is the Material module.");// register with Python
}
~Module() override = default;
private:
};
PyObject* initModule()
{
return Base::Interpreter().addModule(new Module);
}
}// namespace Materials
PyMOD_INIT_FUNC(Material)
{
PyObject* module = Materials::initModule();
Base::Console().Log("Loading Material module... done\n");
Base::Interpreter().addType(&Materials::MaterialManagerPy ::Type, module, "MaterialManager");
Base::Interpreter().addType(&Materials::MaterialPy ::Type, module, "Material");
Base::Interpreter().addType(&Materials::ModelManagerPy ::Type, module, "ModelManager");
Base::Interpreter().addType(&Materials::ModelPropertyPy ::Type, module, "ModelProperty");
Base::Interpreter().addType(&Materials::ModelPy ::Type, module, "Model");
PyMOD_Return(module);
}

View File

@@ -0,0 +1,99 @@
if(MSVC)
add_definitions(-DFCAppMaterial -DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH)
else(MSVC)
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
endif(MSVC)
add_definitions(-DYAML_CPP_STATIC_DEFINE)
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/src
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${Boost_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
${XercesC_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIR}
${YAML_CPP_INCLUDE_DIR}
)
link_directories(${YAML_CPP_LIBRARY_DIR})
set(Material_LIBS
${Boost_LIBRARIES}
FreeCADApp
)
include_directories(
${QtConcurrent_INCLUDE_DIRS}
)
list(APPEND Material_LIBS
${QtConcurrent_LIBRARIES}
${YAML_CPP_LIBRARIES}
)
generate_from_xml(MaterialManagerPy)
generate_from_xml(MaterialPy)
generate_from_xml(ModelManagerPy)
generate_from_xml(ModelPropertyPy)
generate_from_xml(ModelPy)
SET(Python_SRCS
Exceptions.h
MaterialManagerPy.xml
MaterialManagerPyImpl.cpp
MaterialPy.xml
MaterialPyImpl.cpp
ModelManagerPy.xml
ModelManagerPyImpl.cpp
ModelPropertyPy.xml
ModelPropertyPyImpl.cpp
ModelPy.xml
ModelPyImpl.cpp
)
SOURCE_GROUP("Python" FILES ${Python_SRCS})
SET(Material_SRCS
${Python_SRCS}
AppMaterial.cpp
FolderTree.h
MaterialConfigLoader.cpp
MaterialConfigLoader.h
MaterialLibrary.cpp
MaterialLibrary.h
MaterialLoader.cpp
MaterialLoader.h
MaterialManager.cpp
MaterialManager.h
Materials.cpp
Materials.h
MaterialValue.cpp
MaterialValue.h
Model.cpp
Model.h
ModelLibrary.cpp
ModelLibrary.h
ModelLoader.cpp
ModelLoader.h
ModelManager.cpp
ModelManager.h
ModelUuids.h
PreCompiled.cpp
PreCompiled.h
trim.h
)
if(FREECAD_USE_PCH)
add_definitions(-D_PreComp_)
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${Material_SRCS})
ADD_MSVC_PRECOMPILED_HEADER(Material PreCompiled.h PreCompiled.cpp PCH_SRCS)
endif(FREECAD_USE_PCH)
add_library(Material SHARED ${Material_SRCS})
target_link_libraries(Material ${Material_LIBS})
SET_BIN_DIR(Material Material /Mod/Material)
SET_PYTHON_PREFIX_SUFFIX(Material)
INSTALL(TARGETS Material DESTINATION ${CMAKE_INSTALL_LIBDIR})

View File

@@ -0,0 +1,154 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_EXCEPTIONS_H
#define MATERIAL_EXCEPTIONS_H
#include <Base/BaseClass.h>
#include <Base/Exception.h>
namespace Materials
{
class Uninitialized: public Base::Exception
{
public:
Uninitialized()
{}
explicit Uninitialized(const char* msg)
{
this->setMessage(msg);
}
~Uninitialized() throw() override = default;
};
class ModelNotFound: public Base::Exception
{
public:
ModelNotFound()
{}
explicit ModelNotFound(const char* msg)
{
this->setMessage(msg);
}
~ModelNotFound() throw() override = default;
};
class MaterialNotFound: public Base::Exception
{
public:
MaterialNotFound()
{}
explicit MaterialNotFound(const char* msg)
{
this->setMessage(msg);
}
~MaterialNotFound() throw() override = default;
};
class PropertyNotFound: public Base::Exception
{
public:
PropertyNotFound()
{}
explicit PropertyNotFound(const char* msg)
{
this->setMessage(msg);
}
~PropertyNotFound() throw() override = default;
};
class LibraryNotFound: public Base::Exception
{
public:
LibraryNotFound()
{}
explicit LibraryNotFound(const char* msg)
{
this->setMessage(msg);
}
~LibraryNotFound() throw() override = default;
};
class InvalidModel: public Base::Exception
{
public:
InvalidModel()
{}
explicit InvalidModel(const char* msg)
{
this->setMessage(msg);
}
~InvalidModel() throw() override = default;
};
class InvalidRow: public Base::Exception
{
public:
InvalidRow()
{}
explicit InvalidRow(char* msg)
{
this->setMessage(msg);
}
~InvalidRow() throw() override = default;
};
class InvalidColumn: public Base::Exception
{
public:
InvalidColumn()
{}
explicit InvalidColumn(char* msg)
{
this->setMessage(msg);
}
~InvalidColumn() throw() override = default;
};
class InvalidIndex: public Base::Exception
{
public:
InvalidIndex()
{}
explicit InvalidIndex(char* msg)
{
this->setMessage(msg);
}
~InvalidIndex() throw() override = default;
};
class UnknownValueType: public Base::Exception
{
public:
UnknownValueType()
{}
explicit UnknownValueType(char* msg)
{
this->setMessage(msg);
}
~UnknownValueType() throw() override = default;
};
}// namespace Materials
#endif// MATERIAL_EXCEPTIONS_H

View File

@@ -0,0 +1,87 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_FOLDERTREE_H
#define MATERIAL_FOLDERTREE_H
#include <QString>
#include <map>
namespace Materials
{
template<class T>
class FolderTreeNode
{
public:
enum NodeType
{
DataNode,
FolderNode
};
FolderTreeNode()
{}
virtual ~FolderTreeNode() = default;
NodeType getType(void) const
{
return _type;
}
void setType(NodeType type)
{
_type = type;
}
const std::map<QString, FolderTreeNode<T>*>* getFolder(void) const
{
return _folder;
}
std::map<QString, FolderTreeNode<T>*>* getFolder(void)
{
return _folder;
}
const T* getData(void) const
{
return _data;
}
void setFolder(std::map<QString, FolderTreeNode<T>*>* folder)
{
setType(FolderNode);
_folder = folder;
}
void setData(const T* data)
{
setType(DataNode);
_data = data;
}
private:
NodeType _type;
std::map<QString, FolderTreeNode<T>*>* _folder;
const T* _data;
};
}// namespace Materials
#endif// MATERIAL_FOLDERTREE_H

View File

@@ -0,0 +1,396 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QDirIterator>
#include <QFileInfo>
#include <QString>
#endif
#include <QUuid>
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <fstream>
#include "MaterialConfigLoader.h"
#include "MaterialLoader.h"
#include "Model.h"
#include "ModelUuids.h"
using namespace Materials;
MaterialConfigLoader::MaterialConfigLoader()
{}
bool MaterialConfigLoader::isConfigStyle(const QString& path)
{
std::ifstream infile(path.toStdString());
// Check the first 2 lines for a ";"
for (int i = 0; i < 2; i++) {
std::string line;
if (!std::getline(infile, line)) {
return false;
}
if (line.at(0) != ';') {
return false;
}
}
return true;
}
QString MaterialConfigLoader::getAuthorAndLicense(const QString& path)
{
std::ifstream infile(path.toStdString());
QString noAuthor;
// Skip the first line
std::string line;
if (!std::getline(infile, line)) {
return noAuthor;
}
// The second line has it in a comment
if (!std::getline(infile, line)) {
return noAuthor;
}
std::size_t found = line.find(";");
if (found != std::string::npos) {
return QString::fromStdString(trim_copy(line.substr(found + 1)));
}
return noAuthor;
}
void MaterialConfigLoader::addVectorRendering(const QSettings& fcmat, Material* finalModel)
{
QString sectionFillPattern = value(fcmat, "VectorRendering/SectionFillPattern", "");
QString sectionLinewidth = value(fcmat, "VectorRendering/SectionLinewidth", "");
QString sectionColor = value(fcmat, "VectorRendering/SectionColor", "");
QString viewColor = value(fcmat, "VectorRendering/ViewColor", "");
QString viewFillPattern = value(fcmat, "VectorRendering/ViewFillPattern", "");
QString viewLinewidth = value(fcmat, "VectorRendering/ViewLinewidth", "");
if (sectionFillPattern.length() + sectionLinewidth.length() + sectionColor.length()
+ viewColor.length() + viewFillPattern.length() + viewLinewidth.length()
> 0) {
finalModel->addAppearance(ModelUUID_Rendering_Vector);
}
// Now add the data
setAppearanceValue(finalModel, "SectionFillPattern", sectionFillPattern);
setAppearanceValue(finalModel, "SectionLinewidth", sectionLinewidth);
setAppearanceValue(finalModel, "SectionColor", sectionColor);
setAppearanceValue(finalModel, "ViewColor", viewColor);
setAppearanceValue(finalModel, "ViewFillPattern", viewFillPattern);
setAppearanceValue(finalModel, "ViewLinewidth", viewLinewidth);
}
void MaterialConfigLoader::addRendering(const QSettings& fcmat, Material* finalModel)
{
QString ambientColor = value(fcmat, "Rendering/AmbientColor", "");
QString diffuseColor = value(fcmat, "Rendering/DiffuseColor", "");
QString emissiveColor = value(fcmat, "Rendering/EmissiveColor", "");
QString shininess = value(fcmat, "Rendering/Shininess", "");
QString specularColor = value(fcmat, "Rendering/SpecularColor", "");
QString transparency = value(fcmat, "Rendering/Transparency", "");
QString texturePath = value(fcmat, "Rendering/TexturePath", "");
QString textureScaling = value(fcmat, "Rendering/TextureScaling", "");
QString fragmentShader = value(fcmat, "Rendering/FragmentShader", "");
QString vertexShader = value(fcmat, "Rendering/VertexShader", "");
// Check which model we need
bool useTexture = false;
bool useAdvanced = false;
bool useBasic = false;
if (texturePath.length() + textureScaling.length() > 0) {
useTexture = true;
}
if (fragmentShader.length() + vertexShader.length() > 0) {
useAdvanced = true;
}
if (ambientColor.length() + diffuseColor.length() + emissiveColor.length() + shininess.length()
+ specularColor.length() + transparency.length()
> 0) {
useBasic = true;
}
if (useAdvanced) {
finalModel->addAppearance(ModelUUID_Rendering_Advanced);
}
else if (useTexture) {
finalModel->addAppearance(ModelUUID_Rendering_Texture);
}
else if (useBasic) {
finalModel->addAppearance(ModelUUID_Rendering_Basic);
}
// Now add the data
setAppearanceValue(finalModel, "AmbientColor", ambientColor);
setAppearanceValue(finalModel, "DiffuseColor", diffuseColor);
setAppearanceValue(finalModel, "EmissiveColor", emissiveColor);
setAppearanceValue(finalModel, "Shininess", shininess);
setAppearanceValue(finalModel, "SpecularColor", specularColor);
setAppearanceValue(finalModel, "Transparency", transparency);
setAppearanceValue(finalModel, "TexturePath", texturePath);
setAppearanceValue(finalModel, "TextureScaling", textureScaling);
setAppearanceValue(finalModel, "FragmentShader", fragmentShader);
setAppearanceValue(finalModel, "VertexShader", vertexShader);
}
void MaterialConfigLoader::addCosts(const QSettings& fcmat, Material* finalModel)
{
QString productURL = value(fcmat, "Cost/ProductURL", "");
QString specificPrice = value(fcmat, "Cost/SpecificPrice", "");
QString vendor = value(fcmat, "Cost/Vendor", "");
if (productURL.length() + specificPrice.length() + vendor.length() > 0) {
finalModel->addPhysical(ModelUUID_Costs_Default);
}
// Now add the data
setPhysicalValue(finalModel, "ProductURL", productURL);
setPhysicalValue(finalModel, "SpecificPrice", specificPrice);
setPhysicalValue(finalModel, "Vendor", vendor);
}
void MaterialConfigLoader::addArchitectural(const QSettings& fcmat, Material* finalModel)
{
QString color = value(fcmat, "Architectural/Color", "");
QString environmentalEfficiencyClass =
value(fcmat, "Architectural/EnvironmentalEfficiencyClass", "");
QString executionInstructions = value(fcmat, "Architectural/ExecutionInstructions", "");
QString finish = value(fcmat, "Architectural/Finish", "");
QString fireResistanceClass = value(fcmat, "Architectural/FireResistanceClass", "");
QString model = value(fcmat, "Architectural/Model", "");
QString soundTransmissionClass = value(fcmat, "Architectural/SoundTransmissionClass", "");
QString unitsPerQuantity = value(fcmat, "Architectural/UnitsPerQuantity", "");
if (color.length() + environmentalEfficiencyClass.length() + executionInstructions.length()
+ finish.length() + fireResistanceClass.length() + model.length()
+ soundTransmissionClass.length() + unitsPerQuantity.length()
> 0) {
finalModel->addPhysical(ModelUUID_Architectural_Default);
}
// Now add the data
setPhysicalValue(finalModel, "Color", color);
setPhysicalValue(finalModel, "EnvironmentalEfficiencyClass", environmentalEfficiencyClass);
setPhysicalValue(finalModel, "ExecutionInstructions", executionInstructions);
setPhysicalValue(finalModel, "Finish", finish);
setPhysicalValue(finalModel, "FireResistanceClass", fireResistanceClass);
setPhysicalValue(finalModel, "Model", model);
setPhysicalValue(finalModel, "SoundTransmissionClass", soundTransmissionClass);
setPhysicalValue(finalModel, "UnitsPerQuantity", unitsPerQuantity);
}
void MaterialConfigLoader::addElectromagnetic(const QSettings& fcmat, Material* finalModel)
{
QString relativePermittivity = value(fcmat, "Electromagnetic/RelativePermittivity", "");
QString electricalConductivity = value(fcmat, "Electromagnetic/ElectricalConductivity", "");
QString relativePermeability = value(fcmat, "Electromagnetic/RelativePermeability", "");
if (relativePermittivity.length() + electricalConductivity.length()
+ relativePermeability.length()
> 0) {
finalModel->addPhysical(ModelUUID_Electromagnetic_Default);
}
// Now add the data
setPhysicalValue(finalModel, "RelativePermittivity", relativePermittivity);
setPhysicalValue(finalModel, "ElectricalConductivity", electricalConductivity);
setPhysicalValue(finalModel, "RelativePermeability", relativePermeability);
}
void MaterialConfigLoader::addThermal(const QSettings& fcmat, Material* finalModel)
{
QString specificHeat = value(fcmat, "Thermal/SpecificHeat", "");
QString thermalConductivity = value(fcmat, "Thermal/ThermalConductivity", "");
QString thermalExpansionCoefficient = value(fcmat, "Thermal/ThermalExpansionCoefficient", "");
if (specificHeat.length() + thermalConductivity.length() + thermalExpansionCoefficient.length()
> 0) {
finalModel->addPhysical(ModelUUID_Thermal_Default);
}
// Now add the data
setPhysicalValue(finalModel, "SpecificHeat", specificHeat);
setPhysicalValue(finalModel, "ThermalConductivity", thermalConductivity);
setPhysicalValue(finalModel, "ThermalExpansionCoefficient", thermalExpansionCoefficient);
}
void MaterialConfigLoader::addFluid(const QSettings& fcmat, Material* finalModel)
{
QString density = value(fcmat, "Fluidic/Density", "");
QString dynamicViscosity = value(fcmat, "Fluidic/DynamicViscosity", "");
QString kinematicViscosity = value(fcmat, "Fluidic/KinematicViscosity", "");
QString prandtlNumber = value(fcmat, "Fluidic/PrandtlNumber", "");
// Check which model we need
bool useDensity = false;
bool useFluid = false;
if (density.length() > 0) {
useDensity = true;
}
if (dynamicViscosity.length() + kinematicViscosity.length() + prandtlNumber.length() > 0) {
useFluid = true;
}
if (useFluid) {
finalModel->addPhysical(ModelUUID_Fluid_Default);
}
else if (useDensity) {
finalModel->addPhysical(ModelUUID_Mechanical_Density);
}
// Now add the data
setPhysicalValue(finalModel, "Density", density);
setPhysicalValue(finalModel, "DynamicViscosity", dynamicViscosity);
setPhysicalValue(finalModel, "KinematicViscosity", kinematicViscosity);
setPhysicalValue(finalModel, "PrandtlNumber", prandtlNumber);
}
void MaterialConfigLoader::addMechanical(const QSettings& fcmat, Material* finalModel)
{
QString density = value(fcmat, "Mechanical/Density", "");
QString bulkModulus = value(fcmat, "Mechanical/BulkModulus", "");
QString poissonRatio = value(fcmat, "Mechanical/PoissonRatio", "");
QString shearModulus = value(fcmat, "Mechanical/ShearModulus", "");
QString youngsModulus = value(fcmat, "Mechanical/YoungsModulus", "");
QString angleOfFriction = value(fcmat, "Mechanical/AngleOfFriction", "");
QString compressiveStrength = value(fcmat, "Mechanical/CompressiveStrength", "");
QString fractureToughness = value(fcmat, "Mechanical/FractureToughness", "");
QString ultimateStrain = value(fcmat, "Mechanical/UltimateStrain", "");
QString ultimateTensileStrength = value(fcmat, "Mechanical/UltimateTensileStrength", "");
QString yieldStrength = value(fcmat, "Mechanical/YieldStrength", "");
QString stiffness = value(fcmat, "Mechanical/Stiffness", "");
// Check which model we need
bool useDensity = false;
bool useIso = false;
bool useLinearElastic = false;
if (density.length() > 0) {
useDensity = true;
}
if (bulkModulus.length() + poissonRatio.length() + shearModulus.length()
+ youngsModulus.length()
> 0) {
useIso = true;
}
if (angleOfFriction.length() + compressiveStrength.length() + fractureToughness.length()
+ ultimateStrain.length() + ultimateTensileStrength.length() + yieldStrength.length()
+ stiffness.length()
> 0) {
useLinearElastic = true;
}
if (useLinearElastic) {
finalModel->addPhysical(ModelUUID_Mechanical_LinearElastic);
}
else {
if (useIso) {
finalModel->addPhysical(ModelUUID_Mechanical_IsotropicLinearElastic);
}
if (useDensity) {
finalModel->addPhysical(ModelUUID_Mechanical_Density);
}
}
// Now add the data
setPhysicalValue(finalModel, "Density", density);
setPhysicalValue(finalModel, "BulkModulus", bulkModulus);
setPhysicalValue(finalModel, "PoissonRatio", poissonRatio);
setPhysicalValue(finalModel, "ShearModulus", shearModulus);
setPhysicalValue(finalModel, "YoungsModulus", youngsModulus);
setPhysicalValue(finalModel, "AngleOfFriction", angleOfFriction);
setPhysicalValue(finalModel, "CompressiveStrength", compressiveStrength);
setPhysicalValue(finalModel, "FractureToughness", fractureToughness);
setPhysicalValue(finalModel, "UltimateStrain", ultimateStrain);
setPhysicalValue(finalModel, "UltimateTensileStrength", ultimateTensileStrength);
setPhysicalValue(finalModel, "YieldStrength", yieldStrength);
setPhysicalValue(finalModel, "Stiffness", stiffness);
}
Material* MaterialConfigLoader::getMaterialFromPath(const MaterialLibrary& library,
const QString& path)
{
QString authorAndLicense = getAuthorAndLicense(path);
QSettings fcmat(path, QSettings::IniFormat);
// General section
// QString name = value(fcmat, "Name", ""); - always get the name from the filename
QFileInfo filepath(path);
QString name =
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
QString description = value(fcmat, "Description", "");
QString sourceReference = value(fcmat, "ReferenceSource", "");
QString sourceURL = value(fcmat, "SourceURL", "");
Material* finalModel = new Material(library, path, uuid, name);
finalModel->setAuthorAndLicense(authorAndLicense);
finalModel->setDescription(description);
finalModel->setReference(sourceReference);
finalModel->setURL(sourceURL);
QString father = value(fcmat, "Father", "");
if (father.length() > 0) {
finalModel->addPhysical(ModelUUID_Legacy_Father);
// Now add the data
setPhysicalValue(finalModel, "Father", father);
}
QString kindOfMaterial = value(fcmat, "KindOfMaterial", "");
QString materialNumber = value(fcmat, "MaterialNumber", "");
QString norm = value(fcmat, "Norm", "");
QString standardCode = value(fcmat, "StandardCode", "");
if (kindOfMaterial.length() + materialNumber.length() + norm.length() + standardCode.length()
> 0) {
finalModel->addPhysical(ModelUUID_Legacy_MaterialStandard);
// Now add the data
setPhysicalValue(finalModel, "KindOfMaterial", kindOfMaterial);
setPhysicalValue(finalModel, "MaterialNumber", materialNumber);
setPhysicalValue(finalModel, "StandardCode", norm);// Norm is the same as StandardCode
setPhysicalValue(finalModel, "StandardCode", standardCode);
}
// Add the remaining sections
addMechanical(fcmat, finalModel);
addFluid(fcmat, finalModel);
addThermal(fcmat, finalModel);
addElectromagnetic(fcmat, finalModel);
addArchitectural(fcmat, finalModel);
addCosts(fcmat, finalModel);
addRendering(fcmat, finalModel);
addVectorRendering(fcmat, finalModel);
return finalModel;
}

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALCONFIGLOADER_H
#define MATERIAL_MATERIALCONFIGLOADER_H
#include <QDir>
#include <QSettings>
#include <QString>
#include "Materials.h"
namespace Materials
{
class MaterialConfigLoader
{
public:
MaterialConfigLoader();
virtual ~MaterialConfigLoader() = default;
static bool isConfigStyle(const QString& path);
static Material* getMaterialFromPath(const MaterialLibrary& library, const QString& path);
private:
static QString
value(const QSettings& fcmat, const std::string& name, const std::string& defaultValue)
{
return fcmat.value(QString::fromStdString(name), QString::fromStdString(defaultValue))
.toString();
}
static void
setPhysicalValue(Material* finalModel, const std::string& name, const QString& value)
{
if (value.length() > 0) {
finalModel->setPhysicalValue(QString::fromStdString(name), value);
}
}
static void
setAppearanceValue(Material* finalModel, const std::string& name, const QString& value)
{
if (value.length() > 0) {
finalModel->setAppearanceValue(QString::fromStdString(name), value);
}
}
static QString getAuthorAndLicense(const QString& path);
static void addMechanical(const QSettings& fcmat, Material* finalModel);
static void addFluid(const QSettings& fcmat, Material* finalModel);
static void addThermal(const QSettings& fcmat, Material* finalModel);
static void addElectromagnetic(const QSettings& fcmat, Material* finalModel);
static void addArchitectural(const QSettings& fcmat, Material* finalModel);
static void addCosts(const QSettings& fcmat, Material* finalModel);
static void addRendering(const QSettings& fcmat, Material* finalModel);
static void addVectorRendering(const QSettings& fcmat, Material* finalModel);
};
}// namespace Materials
#endif// MATERIAL_MATERIALCONFIGLOADER_H

View File

@@ -0,0 +1,168 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <App/Application.h>
#include "MaterialLibrary.h"
#include "Materials.h"
#include "ModelManager.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
std::map<QString, Material*>* MaterialLibrary::_materialPathMap = nullptr;
TYPESYSTEM_SOURCE(Materials::MaterialLibrary, LibraryBase)
MaterialLibrary::MaterialLibrary()
{
if (_materialPathMap == nullptr) {
_materialPathMap = new std::map<QString, Material*>();
}
}
MaterialLibrary::MaterialLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: LibraryBase(libraryName, dir, icon)
, _readOnly(readOnly)
{
if (_materialPathMap == nullptr) {
_materialPathMap = new std::map<QString, Material*>();
}
}
void MaterialLibrary::createPath(const QString& path)
{
Q_UNUSED(path)
}
Material* MaterialLibrary::saveMaterial(Material& material, const QString& path, bool saveAsCopy)
{
QString filePath = getLocalPath(path);
Base::Console().Log("\tfilePath = '%s'\n", filePath.toStdString().c_str());
QFile file(filePath);
// Update UUID if required
// if name changed true
if (material.getName() != file.fileName()) {
material.newUuid();
}
// if overwrite false having warned the user
// if old format true, but already set
QFileInfo info(file);
QDir fileDir(info.path());
if (!fileDir.exists()) {
if (!fileDir.mkpath(info.path())) {
Base::Console().Error("Unable to create directory path '%s'\n",
info.path().toStdString().c_str());
}
}
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream stream(&file);
stream.setCodec("UTF-8");
stream.setGenerateByteOrderMark(true);
// Write the contents
material.setLibrary(*this);
material.setDirectory(getRelativePath(path));
material.save(stream, saveAsCopy);
}
return addMaterial(material, path);
}
Material* MaterialLibrary::addMaterial(const Material& material, const QString& path)
{
QString filePath = getRelativePath(path);
Material* newMaterial = new Material(material);
newMaterial->setLibrary(*this);
newMaterial->setDirectory(filePath);
try {
// If there's already a material at that path we'll replace it
Material* old = _materialPathMap->at(filePath);
delete old;
}
catch (const std::out_of_range&) {
}
(*_materialPathMap)[filePath] = newMaterial;
return newMaterial;
}
const Material& MaterialLibrary::getMaterialByPath(const QString& path) const
{
// Base::Console().Log("MaterialLibrary::getMaterialByPath(%s)\n", path.toStdString().c_str());
// for (auto itp = _materialPathMap->begin(); itp != _materialPathMap->end(); itp++) {
// Base::Console().Log("\tpath = '%s'\n", itp->first.toStdString().c_str());
// }
QString filePath = getRelativePath(path);
try {
Material* material = _materialPathMap->at(filePath);
return *material;
}
catch (std::out_of_range& e) {
throw MaterialNotFound();
}
}
const QString MaterialLibrary::getUUIDFromPath(const QString& path) const
{
QString filePath = getRelativePath(path);
try {
Material* material = _materialPathMap->at(filePath);
return material->getUUID();
}
catch (std::out_of_range& e) {
throw MaterialNotFound();
}
}
TYPESYSTEM_SOURCE(Materials::MaterialExternalLibrary, MaterialLibrary::MaterialLibrary)
MaterialExternalLibrary::MaterialExternalLibrary()
{}
MaterialExternalLibrary::MaterialExternalLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly)
: MaterialLibrary(libraryName, dir, icon, readOnly)
{}
MaterialExternalLibrary::~MaterialExternalLibrary()
{
// delete directory;
}

View File

@@ -0,0 +1,95 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALLIBRARY_H
#define MATERIAL_MATERIALLIBRARY_H
#include <Base/BaseClass.h>
#include <QDir>
#include <QString>
#include <QVariant>
#include "Model.h"
#include "ModelLibrary.h"
namespace Materials
{
class Material;
class MaterialsExport MaterialLibrary: public LibraryBase
{
TYPESYSTEM_HEADER();
public:
MaterialLibrary();
explicit MaterialLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
virtual ~MaterialLibrary() = default;
bool operator==(const MaterialLibrary& library) const
{
return LibraryBase::operator==(library);
}
bool operator!=(const MaterialLibrary& library) const
{
return !operator==(library);
}
const Material& getMaterialByPath(const QString& path) const;
void createPath(const QString& path);
Material* saveMaterial(Material& material, const QString& path, bool saveAsCopy);
Material* addMaterial(const Material& material, const QString& path);
bool isReadOnly() const
{
return _readOnly;
}
protected:
const QString getUUIDFromPath(const QString& path) const;
bool _readOnly;
static std::map<QString, Material*>* _materialPathMap;
};
class MaterialsExport MaterialExternalLibrary: public MaterialLibrary
{
TYPESYSTEM_HEADER();
public:
MaterialExternalLibrary();
explicit MaterialExternalLibrary(const QString& libraryName,
const QString& dir,
const QString& icon,
bool readOnly = true);
virtual ~MaterialExternalLibrary();
};
}// namespace Materials
Q_DECLARE_METATYPE(Materials::MaterialLibrary)
Q_DECLARE_METATYPE(Materials::MaterialExternalLibrary)
#endif// MATERIAL_MATERIALLIBRARY_H

View File

@@ -0,0 +1,445 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QString>
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <QDirIterator>
#include <QFileInfo>
#include "MaterialConfigLoader.h"
#include "MaterialLoader.h"
#include "Model.h"
#include "ModelManager.h"
using namespace Materials;
MaterialEntry::MaterialEntry()
{}
MaterialEntry::MaterialEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid)
: _library(library)
, _name(modelName)
, _directory(dir)
, _uuid(modelUuid)
{}
MaterialYamlEntry::MaterialYamlEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData)
: MaterialEntry(library, modelName, dir, modelUuid)
, _model(modelData)
{}
// MaterialYamlEntry::~MaterialYamlEntry()
// {}
QString MaterialYamlEntry::yamlValue(const YAML::Node& node,
const std::string& key,
const std::string& defaultValue)
{
if (node[key]) {
return QString::fromStdString(node[key].as<std::string>());
}
return QString::fromStdString(defaultValue);
}
void MaterialYamlEntry::addToTree(std::map<QString, Material*>* materialMap)
{
std::set<QString> exclude;
exclude.insert(QString::fromStdString("General"));
exclude.insert(QString::fromStdString("Inherits"));
auto yamlModel = getModel();
auto library = getLibrary();
auto name = getName();
auto directory = getDirectory();
QString uuid = getUUID();
QString authorAndLicense = yamlValue(yamlModel["General"], "AuthorAndLicense", "");
QString description = yamlValue(yamlModel["General"], "Description", "");
Material* finalModel = new Material(library, directory, uuid, name);
finalModel->setAuthorAndLicense(authorAndLicense);
finalModel->setDescription(description);
// Add inheritance list
if (yamlModel["Inherits"]) {
auto inherits = yamlModel["Inherits"];
for (auto it = inherits.begin(); it != inherits.end(); it++) {
std::string nodeName = it->second["UUID"].as<std::string>();
finalModel->setParentUUID(
QString::fromStdString(nodeName));// Should only be one. Need to check
}
}
// Add material models
if (yamlModel["Models"]) {
auto models = yamlModel["Models"];
for (auto it = models.begin(); it != models.end(); it++) {
std::string modelName = (it->first).as<std::string>();
// Add the model uuid
auto modelNode = models[modelName];
std::string modelUUID = modelNode["UUID"].as<std::string>();
finalModel->addPhysical(QString::fromStdString(modelUUID));
// Add the property values
auto properties = yamlModel["Models"][modelName];
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
std::string propertyName = (itp->first).as<std::string>();
std::string propertyValue = (itp->second).as<std::string>();
if (finalModel->hasPhysicalProperty(QString::fromStdString(propertyName))) {
finalModel->setPhysicalValue(QString::fromStdString(propertyName),
QString::fromStdString(propertyValue));
}
else if (propertyName != "UUID") {
Base::Console().Log("\tProperty '%s' is not described by any model. Ignored\n",
propertyName.c_str());
}
}
}
}
// Add appearance models
if (yamlModel["AppearanceModels"]) {
auto models = yamlModel["AppearanceModels"];
for (auto it = models.begin(); it != models.end(); it++) {
std::string modelName = (it->first).as<std::string>();
// Add the model uuid
auto modelNode = models[modelName];
std::string modelUUID = modelNode["UUID"].as<std::string>();
finalModel->addAppearance(QString::fromStdString(modelUUID));
// Add the property values
auto properties = yamlModel["AppearanceModels"][modelName];
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
std::string propertyName = (itp->first).as<std::string>();
std::string propertyValue = (itp->second).as<std::string>();
if (finalModel->hasAppearanceProperty(QString::fromStdString(propertyName))) {
finalModel->setAppearanceValue(QString::fromStdString(propertyName),
QString::fromStdString(propertyValue));
}
else if (propertyName != "UUID") {
Base::Console().Log("\tProperty '%s' is not described by any model. Ignored\n",
propertyName.c_str());
}
}
}
}
QString path = QDir(directory).absolutePath();
// Base::Console().Log("\tPath '%s'\n", path.toStdString().c_str());
(*materialMap)[uuid] = library.addMaterial(*finalModel, path);
}
std::map<QString, MaterialEntry*>* MaterialLoader::_materialEntryMap = nullptr;
MaterialLoader::MaterialLoader(std::map<QString, Material*>* materialMap,
std::list<MaterialLibrary*>* libraryList)
: _materialMap(materialMap)
, _libraryList(libraryList)
{
loadLibraries();
}
/*
* Destroys the object and frees any allocated resources
*/
MaterialLoader::~MaterialLoader()
{}
void MaterialLoader::addLibrary(MaterialLibrary* model)
{
_libraryList->push_back(model);
}
MaterialEntry* MaterialLoader::getMaterialFromPath(MaterialLibrary& library,
const QString& path) const
{
MaterialEntry* model = nullptr;
// Used for debugging
std::string uuid;
std::string pathName = path.toStdString();
if (MaterialConfigLoader::isConfigStyle(path)) {
Base::Console().Log("Old format .FCMat file: '%s'\n", pathName.c_str());
Material* material = MaterialConfigLoader::getMaterialFromPath(library, path);
if (material) {
(*_materialMap)[material->getUUID()] = library.addMaterial(*material, path);
}
// Return the nullptr as there are no intermediate steps to take, such
// as checking inheritance
return model;
}
YAML::Node yamlroot;
try {
yamlroot = YAML::LoadFile(pathName);
const std::string uuid = yamlroot["General"]["UUID"].as<std::string>();
// Always get the name from the filename
// QString name = QString::fromStdString(yamlroot["General"]["Name"].as<std::string>());
QFileInfo filepath(path);
QString name =
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
model = new MaterialYamlEntry(library, name, path, QString::fromStdString(uuid), yamlroot);
// showYaml(yamlroot);
}
catch (YAML::Exception const& e) {
Base::Console().Error("YAML parsing error: '%s'\n", pathName.c_str());
Base::Console().Error("\t'%s'\n", e.what());
showYaml(yamlroot);
}
return model;
}
void MaterialLoader::showYaml(const YAML::Node& yaml)
{
std::stringstream out;
out << yaml;
std::string logData = out.str();
Base::Console().Log("%s\n", logData.c_str());
}
void MaterialLoader::dereference(Material* material)
{
// Avoid recursion
if (material->getDereferenced()) {
return;
}
// Base::Console().Log("Dereferencing material '%s'.\n",
// material->getName().toStdString().c_str());
auto parentUUID = material->getParentUUID();
if (parentUUID.size() > 0) {
Material* parent;
try {
parent = (*_materialMap)[parentUUID];
}
catch (std::out_of_range& e) {
Base::Console().Log(
"Unable to apply inheritance for material '%s', parent '%s' not found.\n",
material->getName().toStdString().c_str(),
parentUUID.toStdString().c_str());
}
// Ensure the parent has been dereferenced
dereference(parent);
// Add physical models
auto modelVector = parent->getPhysicalModels();
for (auto model = modelVector->begin(); model != modelVector->end(); model++) {
if (!material->hasPhysicalModel(*model)) {
material->addPhysical(*model);
}
}
// Add appearance models
modelVector = parent->getAppearanceModels();
for (auto model = modelVector->begin(); model != modelVector->end(); model++) {
if (!material->hasAppearanceModel(*model)) {
material->addAppearance(*model);
}
}
// Add values
auto properties = parent->getPhysicalProperties();
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
auto name = itp->first;
auto property = static_cast<const MaterialProperty>(itp->second);
if (material->getPhysicalProperty(name).isNull()) {
material->getPhysicalProperty(name).setValue(property.getValue());
}
}
properties = parent->getAppearanceProperties();
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
auto name = itp->first;
auto property = static_cast<const MaterialProperty>(itp->second);
if (material->getAppearanceProperty(name).isNull()) {
material->getAppearanceProperty(name).setValue(property.getValue());
}
}
}
material->markDereferenced();
}
void MaterialLoader::loadLibrary(MaterialLibrary& library)
{
if (_materialEntryMap == nullptr) {
_materialEntryMap = new std::map<QString, MaterialEntry*>();
}
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
while (it.hasNext()) {
auto pathname = it.next();
QFileInfo file(pathname);
if (file.isFile()) {
if (file.suffix().toStdString() == "FCMat") {
QString libraryName = file.baseName();
auto model = getMaterialFromPath(library, file.canonicalFilePath());
if (model) {
(*_materialEntryMap)[model->getUUID()] = model;
}
}
}
}
for (auto it = _materialEntryMap->begin(); it != _materialEntryMap->end(); it++) {
it->second->addToTree(_materialMap);
}
}
void MaterialLoader::loadLibraries(void)
{
std::list<MaterialLibrary*>* _libraryList = getMaterialLibraries();
if (_libraryList) {
for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) {
loadLibrary(**it);
}
}
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
dereference(it->second);
}
}
std::list<MaterialLibrary*>* MaterialLoader::getMaterialLibraries()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources");
bool useBuiltInMaterials = param->GetBool("UseBuiltInMaterials", true);
bool useMatFromModules = param->GetBool("UseMaterialsFromWorkbenches", true);
bool useMatFromConfigDir = param->GetBool("UseMaterialsFromConfigDir", true);
bool useMatFromCustomDir = param->GetBool("UseMaterialsFromCustomDir", true);
if (useBuiltInMaterials) {
QString resourceDir = QString::fromStdString(App::Application::getResourceDir()
+ "/Mod/Material/Resources/Materials");
auto libData = new MaterialLibrary(QString::fromStdString("System"),
resourceDir,
QString::fromStdString(":/icons/freecad.svg"),
true);
_libraryList->push_back(libData);
}
if (useMatFromModules) {
auto moduleParam = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources/Modules");
for (auto& group : moduleParam->GetGroups()) {
// auto module = moduleParam->GetGroup(group->GetGroupName());
auto moduleName = QString::fromStdString(group->GetGroupName());
auto materialDir = QString::fromStdString(group->GetASCII("ModuleDir", ""));
auto materialIcon = QString::fromStdString(group->GetASCII("ModuleIcon", ""));
auto materialReadOnly = group->GetBool("ModuleReadOnly", true);
if (materialDir.length() > 0) {
QDir dir(materialDir);
if (dir.exists()) {
auto libData = new MaterialLibrary(moduleName,
materialDir,
materialIcon,
materialReadOnly);
_libraryList->push_back(libData);
}
}
}
}
if (useMatFromConfigDir) {
QString resourceDir =
QString::fromStdString(App::Application::getUserAppDataDir() + "/Material");
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData =
new MaterialLibrary(QString::fromStdString("User"),
resourceDir,
QString::fromStdString(":/icons/preferences-general.svg"),
false);
_libraryList->push_back(libData);
}
}
}
if (useMatFromCustomDir) {
QString resourceDir = QString::fromStdString(param->GetASCII("CustomMaterialsDir", ""));
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData = new MaterialLibrary(QString::fromStdString("Custom"),
resourceDir,
QString::fromStdString(":/icons/user.svg"),
false);
_libraryList->push_back(libData);
}
}
}
return _libraryList;
}
std::list<QString>* MaterialLoader::getMaterialFolders(const MaterialLibrary& library)
{
std::list<QString>* pathList = new std::list<QString>();
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
while (it.hasNext()) {
auto pathname = it.next();
QFileInfo file(pathname);
if (file.isDir()) {
QString path = QDir(library.getDirectory()).relativeFilePath(file.absoluteFilePath());
if (!path.startsWith(QString::fromStdString("."))) {
pathList->push_back(path);
}
}
}
return pathList;
}

View File

@@ -0,0 +1,129 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALLOADER_H
#define MATERIAL_MATERIALLOADER_H
#include <QDir>
#include <QString>
#include <yaml-cpp/yaml.h>
#include "Materials.h"
#include "trim.h"
namespace Materials
{
class MaterialEntry
{
public:
MaterialEntry();
explicit MaterialEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid);
virtual ~MaterialEntry() = default;
virtual void addToTree(std::map<QString, Material*>* materialMap) = 0;
const MaterialLibrary& getLibrary() const
{
return _library;
}
const QString getName() const
{
return _name;
}
const QString getDirectory() const
{
return _directory;
}
const QString getUUID() const
{
return _uuid;
}
protected:
MaterialLibrary _library;
QString _name;
QString _directory;
QString _uuid;
};
class MaterialYamlEntry: public MaterialEntry
{
public:
explicit MaterialYamlEntry(const MaterialLibrary& library,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData);
~MaterialYamlEntry() override = default;
void addToTree(std::map<QString, Material*>* materialMap) override;
const YAML::Node& getModel() const
{
return _model;
}
YAML::Node* getModelPtr()
{
return &_model;
}
private:
MaterialYamlEntry();
QString
yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue);
YAML::Node _model;
};
class MaterialLoader
{
public:
explicit MaterialLoader(std::map<QString, Material*>* materialMap,
std::list<MaterialLibrary*>* libraryList);
virtual ~MaterialLoader();
std::list<MaterialLibrary*>* getMaterialLibraries();
static std::list<QString>* getMaterialFolders(const MaterialLibrary& library);
static void showYaml(const YAML::Node& yaml);
private:
MaterialLoader();
void addToTree(MaterialEntry* model);
void dereference(Material* material);
MaterialEntry* getMaterialFromPath(MaterialLibrary& library, const QString& path) const;
void addLibrary(MaterialLibrary* model);
void loadLibrary(MaterialLibrary& library);
void loadLibraries(void);
static std::map<QString, MaterialEntry*>* _materialEntryMap;
std::map<QString, Material*>* _materialMap;
std::list<MaterialLibrary*>* _libraryList;
};
}// namespace Materials
#endif// MATERIAL_MATERIALLOADER_H

View File

@@ -0,0 +1,273 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QMutexLocker>
#include <App/Application.h>
#include "Exceptions.h"
#include "MaterialLoader.h"
#include "MaterialManager.h"
#include "ModelManager.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
std::list<MaterialLibrary*>* MaterialManager::_libraryList = nullptr;
std::map<QString, Material*>* MaterialManager::_materialMap = nullptr;
QMutex MaterialManager::_mutex;
TYPESYSTEM_SOURCE(Materials::MaterialManager, Base::BaseClass)
MaterialManager::MaterialManager()
{
// TODO: Add a mutex or similar
initLibraries();
}
void MaterialManager::initLibraries()
{
QMutexLocker locker(&_mutex);
if (_materialMap == nullptr) {
// Load the models first
ModelManager* manager = new ModelManager();
Q_UNUSED(manager)
delete manager;
_materialMap = new std::map<QString, Material*>();
if (_libraryList == nullptr) {
_libraryList = new std::list<MaterialLibrary*>();
}
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
}
}
void MaterialManager::saveMaterial(MaterialLibrary* library,
Material& material,
const QString& path,
bool saveAsCopy)
{
Material* newMaterial = library->saveMaterial(material, path, saveAsCopy);
try {
Material* old = _materialMap->at(newMaterial->getUUID());
if (old) {
delete old;
}
}
catch (const std::out_of_range&) {
}
(*_materialMap)[material.getUUID()] = newMaterial;
}
bool MaterialManager::isMaterial(const fs::path& p)
{
if (!fs::is_regular_file(p)) {
return false;
}
// check file extension
if (p.extension() == ".FCMat") {
return true;
}
return false;
}
const Material& MaterialManager::getMaterial(const QString& uuid) const
{
try {
return *(_materialMap->at(uuid));
}
catch (std::out_of_range& e) {
throw MaterialNotFound();
}
}
const Material& MaterialManager::getMaterialByPath(const QString& path) const
{
QString cleanPath = QDir::cleanPath(path);
for (auto library : *_libraryList) {
Base::Console().Log("MaterialManager::getMaterialByPath() Checking library '%s'->'%s'\n",
library->getName().toStdString().c_str(),
library->getDirectory().toStdString().c_str());
if (cleanPath.startsWith(library->getDirectory())) {
Base::Console().Log("MaterialManager::getMaterialByPath() Library '%s'\n",
library->getDirectory().toStdString().c_str());
Base::Console().Log("MaterialManager::getMaterialByPath() Path '%s'\n",
cleanPath.toStdString().c_str());
return library->getMaterialByPath(cleanPath);
}
}
Base::Console().Log("MaterialManager::getMaterialByPath() Library not found for path '%s'\n",
cleanPath.toStdString().c_str());
throw MaterialNotFound();
}
const Material& MaterialManager::getMaterialByPath(const QString& path, const QString& lib) const
{
auto library = getLibrary(lib); // May throw LibraryNotFound
return library->getMaterialByPath(path);// May throw MaterialNotFound
}
MaterialLibrary* MaterialManager::getLibrary(const QString& name) const
{
for (auto library : *_libraryList) {
if (library->getName() == name) {
return library;
}
}
throw LibraryNotFound();
}
std::list<MaterialLibrary*>* MaterialManager::getMaterialLibraries()
{
if (_libraryList == nullptr) {
if (_materialMap == nullptr) {
_materialMap = new std::map<QString, Material*>();
}
_libraryList = new std::list<MaterialLibrary*>();
// Load the libraries
MaterialLoader loader(_materialMap, _libraryList);
}
return _libraryList;
}
std::map<QString, MaterialTreeNode*>*
MaterialManager::getMaterialTree(const MaterialLibrary& library)
{
std::map<QString, MaterialTreeNode*>* materialTree = new std::map<QString, MaterialTreeNode*>();
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
auto filename = it->first;
auto material = it->second;
if (material->getLibrary() == library) {
fs::path path = material->getDirectory().toStdString();
// Start at the root
std::map<QString, MaterialTreeNode*>* node = materialTree;
for (auto itp = path.begin(); itp != path.end(); itp++) {
if (QString::fromStdString(itp->string())
.endsWith(QString::fromStdString(".FCMat"))) {
MaterialTreeNode* child = new MaterialTreeNode();
child->setData(material);
(*node)[QString::fromStdString(itp->string())] = child;
}
else {
// Add the folder only if it's not already there
QString folderName = QString::fromStdString(itp->string());
std::map<QString, MaterialTreeNode*>* mapPtr;
if (node->count(folderName) == 0) {
mapPtr = new std::map<QString, MaterialTreeNode*>();
MaterialTreeNode* child = new MaterialTreeNode();
child->setFolder(mapPtr);
(*node)[folderName] = child;
node = mapPtr;
}
else {
node = (*node)[folderName]->getFolder();
}
}
}
}
}
std::list<QString>* folderList = getMaterialFolders(library);
for (auto folder : *folderList) {
fs::path path = folder.toStdString();
// Start at the root
std::map<QString, MaterialTreeNode*>* node = materialTree;
for (auto itp = path.begin(); itp != path.end(); itp++) {
// Add the folder only if it's not already there
QString folderName = QString::fromStdString(itp->string());
if (node->count(folderName) == 0) {
std::map<QString, MaterialTreeNode*>* mapPtr =
new std::map<QString, MaterialTreeNode*>();
MaterialTreeNode* child = new MaterialTreeNode();
child->setFolder(mapPtr);
(*node)[folderName] = child;
node = mapPtr;
}
else {
node = (*node)[folderName]->getFolder();
}
}
}
delete folderList;
return materialTree;
}
std::list<QString>* MaterialManager::getMaterialFolders(const MaterialLibrary& library)
{
return MaterialLoader::getMaterialFolders(library);
}
std::map<QString, Material*>* MaterialManager::materialsWithModel(QString uuid)
{
std::map<QString, Material*>* dict = new std::map<QString, Material*>();
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
QString key = it->first;
Material* material = it->second;
if (material->hasModel(uuid)) {
(*dict)[key] = material;
}
}
return dict;
}
std::map<QString, Material*>* MaterialManager::materialsWithModelComplete(QString uuid)
{
std::map<QString, Material*>* dict = new std::map<QString, Material*>();
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
QString key = it->first;
Material* material = it->second;
if (material->isModelComplete(uuid)) {
(*dict)[key] = material;
}
}
return dict;
}

View File

@@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALMANAGER_H
#define MATERIAL_MATERIALMANAGER_H
#include <QMutex>
#include <boost/filesystem.hpp>
#include "FolderTree.h"
#include "Materials.h"
namespace fs = boost::filesystem;
namespace Materials
{
typedef FolderTreeNode<Material> MaterialTreeNode;
class MaterialsExport MaterialManager: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
MaterialManager();
virtual ~MaterialManager() = default;
std::map<QString, Material*>* getMaterials()
{
return _materialMap;
}
const Material& getMaterial(const QString& uuid) const;
const Material& getMaterialByPath(const QString& path) const;
const Material& getMaterialByPath(const QString& path, const QString& library) const;
MaterialLibrary* getLibrary(const QString& name) const;
// Library management
static std::list<MaterialLibrary*>* getMaterialLibraries();
std::map<QString, MaterialTreeNode*>* getMaterialTree(const MaterialLibrary& library);
std::list<QString>* getMaterialFolders(const MaterialLibrary& library);
void createPath(MaterialLibrary* library, const QString& path)
{
library->createPath(path);
}
void saveMaterial(MaterialLibrary* library,
Material& material,
const QString& path,
bool saveAsCopy = true);
static bool isMaterial(const fs::path& p);
std::map<QString, Material*>* materialsWithModel(QString uuid);
std::map<QString, Material*>* materialsWithModelComplete(QString uuid);
private:
static std::list<MaterialLibrary*>* _libraryList;
static std::map<QString, Material*>* _materialMap;
static QMutex _mutex;
static void initLibraries();
};
}// namespace Materials
#endif// MATERIAL_MATERIALMANAGER_H

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateMaterial xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaMaterial_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="MaterialManagerPy"
Twin="MaterialManager"
TwinPointer="MaterialManager"
Include="Mod/Material/App/MaterialManager.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material descriptions.</UserDocu>
</Documentation>
<Methode Name="getMaterial">
<Documentation>
<UserDocu>Get a material object by specifying its UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="getMaterialByPath">
<Documentation>
<UserDocu>Get a material object by specifying its path and library name</UserDocu>
</Documentation>
</Methode>
<Attribute Name="MaterialLibraries" ReadOnly="true">
<Documentation>
<UserDocu>List of Material libraries.</UserDocu>
</Documentation>
<Parameter Name="MaterialLibraries" Type="List"/>
</Attribute>
<Attribute Name="Materials" ReadOnly="true">
<Documentation>
<UserDocu>List of Materials.</UserDocu>
</Documentation>
<Parameter Name="Materials" Type="Dict"/>
</Attribute>
<Methode Name="materialsWithModel">
<Documentation>
<UserDocu>Get a list of materials implementing the specified model</UserDocu>
</Documentation>
</Methode>
<Methode Name="materialsWithModelComplete">
<Documentation>
<UserDocu>Get a list of materials implementing the specified model, with values for all properties</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateMaterial>

View File

@@ -0,0 +1,204 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "Exceptions.h"
#include "MaterialManager.h"
#include "MaterialManagerPy.h"
#include "MaterialPy.h"
#include "Materials.h"
#include "MaterialManagerPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string MaterialManagerPy::representation() const
{
std::stringstream str;
str << "<MaterialManager object at " << getMaterialManagerPtr() << ">";
return str.str();
}
PyObject* MaterialManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new MaterialManagerPy(new MaterialManager());
}
// constructor method
int MaterialManagerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
PyObject* MaterialManagerPy::getMaterial(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
try {
const Material& material =
getMaterialManagerPtr()->getMaterial(QString::fromStdString(uuid));
return new MaterialPy(new Material(material));
}
catch (const MaterialNotFound&) {
PyErr_SetString(PyExc_LookupError, "Material not found");
return nullptr;
}
}
PyObject* MaterialManagerPy::getMaterialByPath(PyObject* args)
{
char* path;
char* lib = "";
if (!PyArg_ParseTuple(args, "s|s", &path, &lib)) {
return nullptr;
}
QString libPath(QString::fromStdString(lib));
if (!libPath.isEmpty()) {
try {
const Material& material =
getMaterialManagerPtr()->getMaterialByPath(QString::fromStdString(path), libPath);
return new MaterialPy(new Material(material));
}
catch (const MaterialNotFound&) {
PyErr_SetString(PyExc_LookupError, "Material not found");
return nullptr;
}
catch (const LibraryNotFound&) {
PyErr_SetString(PyExc_LookupError, "Library not found");
return nullptr;
}
}
try {
const Material& material =
getMaterialManagerPtr()->getMaterialByPath(QString::fromStdString(path));
return new MaterialPy(new Material(material));
}
catch (const MaterialNotFound&) {
PyErr_SetString(PyExc_LookupError, "Material not found");
return nullptr;
}
}
Py::List MaterialManagerPy::getMaterialLibraries() const
{
std::list<MaterialLibrary*>* libraries = getMaterialManagerPtr()->getMaterialLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
MaterialLibrary* lib = *it;
Py::Tuple libTuple(3);
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
list.append(libTuple);
}
return list;
}
Py::Dict MaterialManagerPy::getMaterials() const
{
Py::Dict dict;
std::map<QString, Material*>* materials = getMaterialManagerPtr()->getMaterials();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
Material* material = it->second;
PyObject* materialPy = new MaterialPy(new Material(*material));
dict.setItem(Py::String(key.toStdString()), Py::Object(materialPy, true));
}
// return Py::new_reference_to(dict);
return dict;
}
PyObject* MaterialManagerPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
PyObject* MaterialManagerPy::materialsWithModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
std::map<QString, Material*>* materials =
getMaterialManagerPtr()->materialsWithModel(QString::fromStdString(uuid));
PyObject* dict = PyDict_New();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
Material* material = it->second;
PyObject* materialPy = new MaterialPy(new Material(*material));
PyDict_SetItem(dict, PyUnicode_FromString(key.toStdString().c_str()), materialPy);
}
delete materials;
return dict;
}
PyObject* MaterialManagerPy::materialsWithModelComplete(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
std::map<QString, Material*>* materials =
getMaterialManagerPtr()->materialsWithModelComplete(QString::fromStdString(uuid));
PyObject* dict = PyDict_New();
for (auto it = materials->begin(); it != materials->end(); it++) {
QString key = it->first;
Material* material = it->second;
PyObject* materialPy = new MaterialPy(new Material(*material));
PyDict_SetItem(dict, PyUnicode_FromString(key.toStdString().c_str()), materialPy);
}
delete materials;
return dict;
}

View File

@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="MaterialPy"
Twin="Material"
TwinPointer="Material"
Include="Mod/Material/App/Materials.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material descriptions.</UserDocu>
</Documentation>
<Attribute Name="LibraryName" ReadOnly="true">
<Documentation>
<UserDocu>Model library name.</UserDocu>
</Documentation>
<Parameter Name="LibraryName" Type="String"/>
</Attribute>
<Attribute Name="LibraryRoot" ReadOnly="true">
<Documentation>
<UserDocu>Model library path.</UserDocu>
</Documentation>
<Parameter Name="LibraryRoot" Type="String"/>
</Attribute>
<Attribute Name="LibraryIcon" ReadOnly="true">
<Documentation>
<UserDocu>Model icon path.</UserDocu>
</Documentation>
<Parameter Name="LibraryIcon" Type="String"/>
</Attribute>
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>Model name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="true">
<Documentation>
<UserDocu>Model directory relative to the library root.</UserDocu>
</Documentation>
<Parameter Name="Directory" Type="String"/>
</Attribute>
<Attribute Name="UUID" ReadOnly="true">
<Documentation>
<UserDocu>Unique model identifier.</UserDocu>
</Documentation>
<Parameter Name="UUID" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>Description of the material.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Documentation>
<UserDocu>URL to a material reference.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="Reference" ReadOnly="true">
<Documentation>
<UserDocu>Reference for material data.</UserDocu>
</Documentation>
<Parameter Name="Reference" Type="String"/>
</Attribute>
<Attribute Name="Parent" ReadOnly="true">
<Documentation>
<UserDocu>Parent material UUID.</UserDocu>
</Documentation>
<Parameter Name="Parent" Type="String"/>
</Attribute>
<Attribute Name="AuthorAndLicense" ReadOnly="true">
<Documentation>
<UserDocu>Author and license information.</UserDocu>
</Documentation>
<Parameter Name="AuthorAndLicense" Type="String"/>
</Attribute>
<Attribute Name="PhysicalModels" ReadOnly="true">
<Documentation>
<UserDocu>List of implemented models.</UserDocu>
</Documentation>
<Parameter Name="PhysicalModels" Type="List"/>
</Attribute>
<Attribute Name="AppearanceModels" ReadOnly="true">
<Documentation>
<UserDocu>List of implemented models.</UserDocu>
</Documentation>
<Parameter Name="AppearanceModels" Type="List"/>
</Attribute>
<Attribute Name="Tags" ReadOnly="true">
<Documentation>
<UserDocu>List of searchable tags.</UserDocu>
</Documentation>
<Parameter Name="Tags" Type="List"/>
</Attribute>
<Methode Name="hasPhysicalModel" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the physical model with the given UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasAppearanceModel" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the appearance model with the given UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="isPhysicalModelComplete" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the physical model with the given UUID, and has values defined for each property</UserDocu>
</Documentation>
</Methode>
<Methode Name="isAppearanceModelComplete" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the appearance model with the given UUID, and has values defined for each property</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasPhysicalProperty" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the physical property with the given name</UserDocu>
</Documentation>
</Methode>
<Methode Name="hasAppearanceProperty" ReadOnly="true">
<Documentation>
<UserDocu>Check if the material implements the appearance property with the given name</UserDocu>
</Documentation>
</Methode>
<Attribute Name="Properties" ReadOnly="true">
<Documentation>
<UserDocu>deprecated -- Dictionary of all material properties.</UserDocu>
</Documentation>
<Parameter Name="Properties" Type="Dict"/>
</Attribute>
<Attribute Name="PhysicalProperties" ReadOnly="true">
<Documentation>
<UserDocu>deprecated -- Dictionary of material physical properties.</UserDocu>
</Documentation>
<Parameter Name="PhysicalProperties" Type="Dict"/>
</Attribute>
<Attribute Name="AppearanceProperties" ReadOnly="true">
<Documentation>
<UserDocu>deprecated -- Dictionary of material appearance properties.</UserDocu>
</Documentation>
<Parameter Name="AppearanceProperties" Type="Dict"/>
</Attribute>
<Methode Name="getPhysicalValue" ReadOnly="true">
<Documentation>
<UserDocu>Get the value associated with the property</UserDocu>
</Documentation>
</Methode>
<Methode Name="getAppearanceValue" ReadOnly="true">
<Documentation>
<UserDocu>Get the value associated with the property</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,395 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include <QMetaType>
#include <Base/Quantity.h>
#include <Base/QuantityPy.h>
#include <Gui/MetaTypes.h>
#include "Exceptions.h"
#include "MaterialPy.h"
#include "Materials.h"
#include "MaterialPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string MaterialPy::representation() const
{
MaterialPy::PointerType ptr = getMaterialPtr();
std::stringstream str;
str << "Property [Name=(";
str << ptr->getName().toStdString();
str << "), UUID=(";
str << ptr->getUUID().toStdString();
str << "), Library Name=(";
str << ptr->getLibrary().getName().toStdString();
str << "), Library Root=(";
str << ptr->getLibrary().getDirectoryPath().toStdString();
str << "), Library Icon=(";
str << ptr->getLibrary().getIconPath().toStdString();
str << "), Directory=(";
str << ptr->getDirectory().toStdString();
// str << "), URL=(";
// str << ptr->getURL();
// str << "), DOI=(";
// str << ptr->getDOI();
// str << "), Description=(";
// str << ptr->getDescription();
// str << "), Inherits=[";
// const std::vector<std::string> &inherited = getMaterialPtr()->getInheritance();
// for (auto it = inherited.begin(); it != inherited.end(); it++)
// {
// std::string uuid = *it;
// if (it != inherited.begin())
// str << "), UUID=(";
// else
// str << "UUID=(";
// str << uuid << ")";
// }
// str << "]]";
str << ")]";
return str.str();
}
PyObject* MaterialPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new MaterialPy(new Material());
}
// constructor method
int MaterialPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String MaterialPy::getLibraryName() const
{
return Py::String(getMaterialPtr()->getLibrary().getName().toStdString());
}
Py::String MaterialPy::getLibraryRoot() const
{
return Py::String(getMaterialPtr()->getLibrary().getDirectoryPath().toStdString());
}
Py::String MaterialPy::getLibraryIcon() const
{
return Py::String(getMaterialPtr()->getLibrary().getIconPath().toStdString());
}
Py::String MaterialPy::getName() const
{
return Py::String(getMaterialPtr()->getName().toStdString());
}
Py::String MaterialPy::getDirectory() const
{
return Py::String(getMaterialPtr()->getDirectory().toStdString());
}
Py::String MaterialPy::getUUID() const
{
return Py::String(getMaterialPtr()->getUUID().toStdString());
}
Py::String MaterialPy::getDescription() const
{
return Py::String(getMaterialPtr()->getDescription().toStdString());
}
Py::String MaterialPy::getURL() const
{
return Py::String(getMaterialPtr()->getURL().toStdString());
}
Py::String MaterialPy::getReference() const
{
return Py::String(getMaterialPtr()->getReference().toStdString());
}
Py::String MaterialPy::getParent() const
{
return Py::String(getMaterialPtr()->getParentUUID().toStdString());
}
Py::String MaterialPy::getAuthorAndLicense() const
{
return Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString());
}
Py::List MaterialPy::getPhysicalModels() const
{
const std::vector<QString>* models = getMaterialPtr()->getPhysicalModels();
Py::List list;
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
Py::List MaterialPy::getAppearanceModels() const
{
const std::vector<QString>* models = getMaterialPtr()->getAppearanceModels();
Py::List list;
for (auto it = models->begin(); it != models->end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
Py::List MaterialPy::getTags() const
{
const std::list<QString>& tags = getMaterialPtr()->getTags();
Py::List list;
for (auto it = tags.begin(); it != tags.end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
PyObject* MaterialPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int MaterialPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}
PyObject* MaterialPy::hasPhysicalModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasPhysicalModel(QString::fromStdString(uuid));
return hasProperty ? Py_True : Py_False;
}
PyObject* MaterialPy::hasAppearanceModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasAppearanceModel(QString::fromStdString(uuid));
return hasProperty ? Py_True : Py_False;
}
PyObject* MaterialPy::isPhysicalModelComplete(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool isComplete = getMaterialPtr()->isPhysicalModelComplete(QString::fromStdString(name));
return isComplete ? Py_True : Py_False;
}
PyObject* MaterialPy::isAppearanceModelComplete(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool isComplete = getMaterialPtr()->isAppearanceModelComplete(QString::fromStdString(name));
return isComplete ? Py_True : Py_False;
}
PyObject* MaterialPy::hasPhysicalProperty(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasPhysicalProperty(QString::fromStdString(name));
return hasProperty ? Py_True : Py_False;
}
PyObject* MaterialPy::hasAppearanceProperty(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
bool hasProperty = getMaterialPtr()->hasAppearanceProperty(QString::fromStdString(name));
return hasProperty ? Py_True : Py_False;
}
Py::Dict MaterialPy::getProperties() const
{
Py::Dict dict;
// Maintain backwards compatibility
dict.setItem(Py::String("CardName"), Py::String(getMaterialPtr()->getName().toStdString()));
dict.setItem(Py::String("AuthorAndLicense"),
Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString()));
dict.setItem(Py::String("Name"), Py::String(getMaterialPtr()->getName().toStdString()));
dict.setItem(Py::String("Description"),
Py::String(getMaterialPtr()->getDescription().toStdString()));
dict.setItem(Py::String("ReferenceSource"),
Py::String(getMaterialPtr()->getReference().toStdString()));
dict.setItem(Py::String("SourceURL"), Py::String(getMaterialPtr()->getURL().toStdString()));
auto properties = getMaterialPtr()->getPhysicalProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
properties = getMaterialPtr()->getAppearanceProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
return dict;
}
Py::Dict MaterialPy::getPhysicalProperties() const
{
Py::Dict dict;
auto properties = getMaterialPtr()->getPhysicalProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
return dict;
}
Py::Dict MaterialPy::getAppearanceProperties() const
{
Py::Dict dict;
auto properties = getMaterialPtr()->getAppearanceProperties();
for (auto it = properties.begin(); it != properties.end(); it++) {
QString key = it->first;
MaterialProperty& materialProperty = it->second;
if (!materialProperty.isNull()) {
auto value = materialProperty.getString();
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
}
}
return dict;
}
static PyObject* _pyObjectFromVariant(const QVariant& value)
{
if (value.isNull()) {
return new PyObject();
}
if (value.userType() == QMetaType::type("Base::Quantity")) {
return new Base::QuantityPy(new Base::Quantity(value.value<Base::Quantity>()));
}
else if (value.userType() == QMetaType::Double) {
return PyFloat_FromDouble(value.toDouble());
}
else if (value.userType() == QMetaType::Float) {
return PyFloat_FromDouble(value.toFloat());
}
else if (value.userType() == QMetaType::Int) {
return PyLong_FromLong(value.toInt());
}
else if (value.userType() == QMetaType::Long) {
return PyLong_FromLong(value.toInt());
}
else if (value.userType() == QMetaType::Bool) {
return value.toBool() ? Py_True : Py_False;
}
else if (value.userType() == QMetaType::QString) {
return PyUnicode_FromString(value.toString().toStdString().c_str());
}
throw UnknownValueType();
}
PyObject* MaterialPy::getPhysicalValue(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
QVariant value = getMaterialPtr()->getPhysicalValue(QString::fromStdString(name));
return _pyObjectFromVariant(value);
}
PyObject* MaterialPy::getAppearanceValue(PyObject* args)
{
char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return nullptr;
}
QVariant value = getMaterialPtr()->getAppearanceValue(QString::fromStdString(name));
return _pyObjectFromVariant(value);
}

View File

@@ -0,0 +1,243 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <App/Application.h>
#include "Exceptions.h"
#include "MaterialValue.h"
using namespace Materials;
/* TRANSLATOR Material::MaterialValue */
MaterialValue::MaterialValue()
: _valueType(None)
{}
MaterialValue::MaterialValue(ValueType type)
: _valueType(type)
{}
//===
Material2DArray::Material2DArray()
: MaterialValue(Array2D)
, _defaultSet(false)
{}
MaterialValue Material2DArray::getDefault() const
{
MaterialValue ret(_valueType);
ret.setValue(_value);
return ret;
}
const std::vector<QVariant>* Material2DArray::getRow(int row) const
{
try {
return _rows.at(row);
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
std::vector<QVariant>* Material2DArray::getRow(int row)
{
try {
return _rows.at(row);
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
void Material2DArray::addRow(std::vector<QVariant>* row)
{
_rows.push_back(row);
}
void Material2DArray::insertRow(int index, std::vector<QVariant>* row)
{
_rows.insert(_rows.begin() + index, row);
}
void Material2DArray::deleteRow(int row)
{
if (static_cast<std::size_t>(row) >= _rows.size() || row < 0) {
throw InvalidRow();
}
_rows.erase(_rows.begin() + row);
}
void Material2DArray::setValue(int row, int column, const QVariant& value)
{
if (row >= rows()) {
throw InvalidIndex();
}
std::vector<QVariant>* val = getRow(row);
try {
val->at(column) = value;
}
catch (const std::out_of_range&) {
throw InvalidIndex();
}
}
const QVariant Material2DArray::getValue(int row, int column)
{
try {
auto val = getRow(row);
try {
return val->at(column);
}
catch (std::out_of_range const&) {
throw InvalidIndex();
}
}
catch (const InvalidRow&) {
throw InvalidIndex();
}
}
void Material2DArray::dumpRow(const std::vector<QVariant>& row) const
{
Base::Console().Log("row: ");
for (auto column : row) {
Base::Console().Log("'%s' ", column.toString().toStdString().c_str());
}
Base::Console().Log("\n");
}
void Material2DArray::dump() const
{
for (auto row : _rows) {
dumpRow(*row);
}
}
//===
Material3DArray::Material3DArray()
: MaterialValue(Array3D)
, _defaultSet(false)
{}
MaterialValue Material3DArray::getDefault() const
{
MaterialValue ret(_valueType);
ret.setValue(_value);
return ret;
}
const std::vector<std::vector<QVariant>*>& Material3DArray::getTable(const QVariant& depth) const
{
try {
return _rowMap.at(depth);
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
const std::vector<QVariant>& Material3DArray::getRow(const QVariant& depth, int row) const
{
try {
return *(_rowMap.at(depth).at(row));
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
const std::vector<QVariant>& Material3DArray::getRow(int row) const
{
return getRow(getDefault().getValue().toString(), row);
}
std::vector<QVariant>& Material3DArray::getRow(const QVariant& depth, int row)
{
try {
return *(_rowMap.at(depth).at(row));
}
catch (std::out_of_range const&) {
throw InvalidRow();
}
}
std::vector<QVariant>& Material3DArray::getRow(int row)
{
return getRow(getDefault().getValue().toString(), row);
}
void Material3DArray::addRow(const QVariant& depth, std::vector<QVariant>* row)
{
_rowMap[depth].push_back(row);
}
void Material3DArray::deleteRow(const QVariant& depth, int row)
{
Q_UNUSED(depth)
Q_UNUSED(row)
}
void Material3DArray::deleteRows(int depth)
{
Q_UNUSED(depth)
}
void Material3DArray::setValue(const QVariant& depth, int row, int column, const QVariant& value)
{
Q_UNUSED(depth)
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(value)
}
void Material3DArray::setValue(int row, int column, const QVariant& value)
{
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(value)
}
const QVariant Material3DArray::getValue(const QVariant& depth, int row, int column)
{
auto val = getRow(depth, row);
try {
return val.at(column);
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
const QVariant Material3DArray::getValue(int row, int column)
{
return getValue(getDefault().getValue().toString(), row, column);
}

View File

@@ -0,0 +1,187 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALVALUE_H
#define MATERIAL_MATERIALVALUE_H
#include <QVariant>
namespace Materials
{
class MaterialsExport MaterialValue
{
public:
enum ValueType
{
None = 0,
String = 1,
Boolean = 2,
Integer = 3,
Float = 4,
Quantity = 5,
Distribution = 6,
List = 7,
Array2D = 8,
Array3D = 9,
Color = 10,
Image = 11,
File = 12,
URL = 13
};
MaterialValue();
explicit MaterialValue(ValueType type);
virtual ~MaterialValue() = default;
ValueType getType()
{
return _valueType;
}
const QVariant getValue(void) const
{
return _value;
}
bool isNull() const
{
return _value.isNull();
}
virtual const QVariant getValueAt(const QVariant& value) const
{
Q_UNUSED(value);
return _value;
}
void setValue(const QVariant& value)
{
_value = value;
}
protected:
ValueType _valueType;
QVariant _value;
void setType(ValueType type)
{
_valueType = type;
}
};
class MaterialsExport Material2DArray: public MaterialValue
{
public:
Material2DArray();
~Material2DArray() override = default;
void setDefault(MaterialValue value)
{
_value = value.getValue();
_defaultSet = true;
}
void setDefault(const QVariant& value)
{
_value = value;
_defaultSet = true;
}
MaterialValue getDefault() const;
bool defaultSet() const
{
return _defaultSet;
}
const std::vector<QVariant>* getRow(int row) const;
std::vector<QVariant>* getRow(int row);
int rows() const
{
return _rows.size();
}
void addRow(std::vector<QVariant>* row);
void insertRow(int index, std::vector<QVariant>* row);
void deleteRow(int row);
void setValue(int row, int column, const QVariant& value);
const QVariant getValue(int row, int column);
protected:
std::vector<std::vector<QVariant>*> _rows;
bool _defaultSet;
private:
void dumpRow(const std::vector<QVariant>& row) const;
void dump() const;
};
class MaterialsExport Material3DArray: public MaterialValue
{
public:
Material3DArray();
~Material3DArray() override = default;
void setDefault(MaterialValue value)
{
_value = value.getValue();
_defaultSet = true;
}
void setDefault(const QVariant& value)
{
_value = value;
_defaultSet = true;
}
MaterialValue getDefault() const;
bool defaultSet() const
{
return _defaultSet;
}
const std::vector<std::vector<QVariant>*>& getTable(const QVariant& depth) const;
const std::vector<QVariant>& getRow(const QVariant& depth, int row) const;
const std::vector<QVariant>& getRow(int row) const;
std::vector<QVariant>& getRow(const QVariant& depth, int row);
std::vector<QVariant>& getRow(int row);
void addRow(const QVariant& depth, std::vector<QVariant>* row);
void deleteRow(const QVariant& depth, int row);
void deleteRows(int depth);
int depth() const
{
return _rowMap.size();
}
int rows(const QVariant& depth) const
{
return getTable(depth).size();
}
void setValue(const QVariant& depth, int row, int column, const QVariant& value);
void setValue(int row, int column, const QVariant& value);
const QVariant getValue(const QVariant& depth, int row, int column);
const QVariant getValue(int row, int column);
protected:
std::map<QVariant, std::vector<std::vector<QVariant>*>> _rowMap;
bool _defaultSet;
};
}// namespace Materials
Q_DECLARE_METATYPE(Materials::MaterialValue)
Q_DECLARE_METATYPE(Materials::Material2DArray)
Q_DECLARE_METATYPE(Materials::Material3DArray)
#endif// MATERIAL_MATERIALVALUE_H

View File

@@ -0,0 +1,914 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QMetaType>
#include <QUuid>
#include <App/Application.h>
#include <Gui/MetaTypes.h>
#include "MaterialManager.h"
#include "Materials.h"
#include "ModelManager.h"
using namespace Materials;
/* TRANSLATOR Material::Materials */
TYPESYSTEM_SOURCE(Materials::MaterialProperty, Materials::ModelProperty)
MaterialProperty::MaterialProperty()
{
_valuePtr = new MaterialValue(MaterialValue::None);
}
MaterialProperty::MaterialProperty(const ModelProperty& property)
: ModelProperty(property)
, _valuePtr(nullptr)
{
setType(getPropertyType());
auto columns = property.getColumns();
for (std::vector<ModelProperty>::const_iterator it = columns.begin(); it != columns.end();
it++) {
MaterialProperty prop(*it);
addColumn(prop);
}
if (_valuePtr->getType() == MaterialValue::Array2D) {
reinterpret_cast<Material2DArray*>(_valuePtr)->setDefault(getColumnNull(0));
}
else if (_valuePtr->getType() == MaterialValue::Array3D) {
reinterpret_cast<Material3DArray*>(_valuePtr)->setDefault(getColumnNull(0));
}
}
MaterialProperty::MaterialProperty(const MaterialProperty& other)
: ModelProperty(other)
{
_modelUUID = other._modelUUID;
if (other._valuePtr != nullptr) {
_valuePtr = new MaterialValue(*(other._valuePtr));
}
else {
_valuePtr = nullptr;
}
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
}
MaterialProperty::~MaterialProperty()
{}
void MaterialProperty::setModelUUID(const QString& uuid)
{
_modelUUID = uuid;
}
const QVariant MaterialProperty::getValue(void) const
{
return _valuePtr->getValue();
}
MaterialValue* MaterialProperty::getMaterialValue(void)
{
return _valuePtr;
}
const QString MaterialProperty::getString(void) const
{
if (getType() == MaterialValue::Quantity) {
Base::Quantity quantity = getValue().value<Base::Quantity>();
return quantity.getUserString();
}
return getValue().toString();
}
void MaterialProperty::setPropertyType(const QString& type)
{
ModelProperty::setPropertyType(type);
setType(type);
}
void MaterialProperty::setType(const QString& type)
{
if (_valuePtr) {
delete _valuePtr;
}
if (type == QString::fromStdString("String")) {
_valuePtr = new MaterialValue(MaterialValue::String);
}
else if (type == QString::fromStdString("Boolean")) {
_valuePtr = new MaterialValue(MaterialValue::Boolean);
}
else if (type == QString::fromStdString("Integer")) {
_valuePtr = new MaterialValue(MaterialValue::Integer);
}
else if (type == QString::fromStdString("Float")) {
_valuePtr = new MaterialValue(MaterialValue::Float);
}
else if (type == QString::fromStdString("URL")) {
_valuePtr = new MaterialValue(MaterialValue::URL);
}
else if (type == QString::fromStdString("Quantity")) {
_valuePtr = new MaterialValue(MaterialValue::Quantity);
}
else if (type == QString::fromStdString("Color")) {
_valuePtr = new MaterialValue(MaterialValue::Color);
}
else if (type == QString::fromStdString("File")) {
_valuePtr = new MaterialValue(MaterialValue::File);
}
else if (type == QString::fromStdString("Image")) {
_valuePtr = new MaterialValue(MaterialValue::Image);
}
else if (type == QString::fromStdString("List")) {
_valuePtr = new MaterialValue(MaterialValue::List);
}
else if (type == QString::fromStdString("2DArray")) {
_valuePtr = new Material2DArray();
}
else if (type == QString::fromStdString("3DArray")) {
_valuePtr = new Material3DArray();
}
else {
// Error. Throw something
_valuePtr = new MaterialValue(MaterialValue::None);
std::string stringType = type.toStdString();
std::string name = getName().toStdString();
throw UnknownValueType();
}
}
MaterialProperty& MaterialProperty::getColumn(int column)
{
try {
return _columns.at(column);
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
MaterialValue::ValueType MaterialProperty::getColumnType(int column) const
{
try {
return _columns.at(column).getType();
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
QString MaterialProperty::getColumnUnits(int column) const
{
try {
return _columns.at(column).getUnits();
}
catch (std::out_of_range const&) {
throw InvalidColumn();
}
}
QVariant MaterialProperty::getColumnNull(int column) const
{
MaterialValue::ValueType valueType = getColumnType(column);
switch (valueType) {
case MaterialValue::Quantity: {
Base::Quantity q = Base::Quantity(0, getColumnUnits(column));
return QVariant::fromValue(q);
}
case MaterialValue::Float:
case MaterialValue::Integer:
return QVariant(0);
default:
break;
}
return QVariant(QString());
}
void MaterialProperty::setValue(const QVariant& value)
{
// _valueType = MaterialValue::String;
_valuePtr->setValue(value);
}
void MaterialProperty::setValue(const QString& value)
{
if (_valuePtr->getType() == MaterialValue::Boolean) {
setBoolean(value);
}
else if (_valuePtr->getType() == MaterialValue::Integer) {
setInt(value);
}
else if (_valuePtr->getType() == MaterialValue::Float) {
setFloat(value);
}
else if (_valuePtr->getType() == MaterialValue::URL) {
setURL(value);
}
else if (_valuePtr->getType() == MaterialValue::Quantity) {
// Base::Console().Log("\tParse quantity '%s'\n", value.toStdString().c_str());
try {
setQuantity(Base::Quantity::parse(value));
}
catch (const Base::ParserError& e) {
Base::Console().Log("Error '%s'\n", e.what());
// Save as a string
setString(value);
}
}
else {
setString(value);
}
}
void MaterialProperty::setString(const QString& value)
{
// _valueType = MaterialValue::String;
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setBoolean(bool value)
{
// _valueType = MaterialValue::Boolean;
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setBoolean(int value)
{
// _valueType = MaterialValue::Boolean;
_valuePtr->setValue(QVariant(value != 0));
}
void MaterialProperty::setBoolean(const QString& value)
{
// _valueType = MaterialValue::Boolean;
bool boolean;
std::string val = value.toStdString();
if ((val == "true") || (val == "True")) {
boolean = true;
}
else if ((val == "false") || (val == "False")) {
boolean = false;
}
else {
boolean = (std::stoi(val) != 0);
}
setBoolean(boolean);
}
void MaterialProperty::setInt(int value)
{
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setInt(const QString& value)
{
_valuePtr->setValue(value.toInt());
}
void MaterialProperty::setFloat(double value)
{
_valuePtr->setValue(QVariant(value));
}
void MaterialProperty::setFloat(const QString& value)
{
_valuePtr->setValue(QVariant(value.toFloat()));
}
void MaterialProperty::setQuantity(const Base::Quantity& value)
{
_valuePtr->setValue(QVariant(QVariant::fromValue(value)));
}
void MaterialProperty::setQuantity(double value, const QString& units)
{
setQuantity(Base::Quantity(value, units));
}
void MaterialProperty::setQuantity(const QString& value)
{
setQuantity(Base::Quantity::parse(value));
}
void MaterialProperty::setURL(const QString& value)
{
_valuePtr->setValue(QVariant(value));
}
MaterialProperty& MaterialProperty::operator=(const MaterialProperty& other)
{
if (this == &other) {
return *this;
}
ModelProperty::operator=(other);
_modelUUID = other._modelUUID;
delete _valuePtr;
if (other._valuePtr != nullptr) {
_valuePtr = new MaterialValue(*(other._valuePtr));
}
else {
_valuePtr = nullptr;
}
_columns.clear();
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
return *this;
}
TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass)
Material::Material()
: _dereferenced(false)
{}
Material::Material(const MaterialLibrary& library,
const QString& directory,
const QString& uuid,
const QString& name)
: _library(library)
, _uuid(uuid)
, _name(name)
, _dereferenced(false)
, _editState(ModelEdit_None)
{
setDirectory(directory);
}
Material::Material(const Material& other)
: _library(other._library)
, _directory(other._directory)
, _uuid(other._uuid)
, _name(other._name)
, _authorAndLicense(other._authorAndLicense)
, _parentUuid(other._parentUuid)
, _description(other._description)
, _url(other._url)
, _reference(other._reference)
, _dereferenced(other._dereferenced)
, _editState(other._editState)
{
for (auto it = other._tags.begin(); it != other._tags.end(); it++) {
_tags.push_back(*it);
}
for (auto it = other._physicalUuids.begin(); it != other._physicalUuids.end(); it++) {
_physicalUuids.push_back(*it);
}
for (auto it = other._appearanceUuids.begin(); it != other._appearanceUuids.end(); it++) {
_appearanceUuids.push_back(*it);
}
for (auto it = other._allUuids.begin(); it != other._allUuids.end(); it++) {
_allUuids.push_back(*it);
}
for (auto it = other._physical.begin(); it != other._physical.end(); it++) {
_physical[it->first] = MaterialProperty(it->second);
}
for (auto it = other._appearance.begin(); it != other._appearance.end(); it++) {
_appearance[it->first] = MaterialProperty(it->second);
}
}
/*
* Destroys the object and frees any allocated resources
*/
Material::~Material()
{
// no need to delete child widgets, Qt does it all for us
}
void Material::addModel(const QString& uuid)
{
for (QString modelUUID : _allUuids) {
if (modelUUID == uuid) {
return;
}
}
_allUuids.push_back(uuid);
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
auto inheritance = model.getInheritance();
for (auto inherits = inheritance.begin(); inherits != inheritance.end(); inherits++) {
addModel(*inherits);
}
}
catch (ModelNotFound const&) {
}
}
void Material::setEditState(ModelEdit newState)
{
if (newState == ModelEdit_Extend) {
if (_editState != ModelEdit_Alter) {
_editState = newState;
}
}
else if (newState == ModelEdit_Alter) {
_editState = newState;
}
}
void Material::addPhysical(const QString& uuid)
{
if (hasPhysicalModel(uuid)) {
return;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
_physicalUuids.push_back(uuid);
addModel(uuid);
setEditStateExtend();
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
ModelProperty property = static_cast<ModelProperty>(it->second);
try {
_physical[propertyName] = MaterialProperty(property);
}
catch (const UnknownValueType&) {
Base::Console().Error("Property '%s' has unknown type '%s'. Ignoring\n",
property.getName().toStdString().c_str(),
property.getPropertyType().toStdString().c_str());
}
}
}
catch (ModelNotFound const&) {
}
}
void Material::addAppearance(const QString& uuid)
{
if (hasAppearanceModel(uuid)) {
return;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
_appearanceUuids.push_back(uuid);
addModel(uuid);
setEditStateExtend();
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
ModelProperty property = static_cast<ModelProperty>(it->second);
_appearance[propertyName] = MaterialProperty(property);
}
}
catch (ModelNotFound const&) {
}
}
void Material::setPhysicalEditState(const QString& name)
{
if (getPhysicalProperty(name).isNull()) {
setEditStateExtend();
}
else {
setEditStateAlter();
}
}
void Material::setAppearanceEditState(const QString& name)
{
if (getAppearanceProperty(name).isNull()) {
setEditStateExtend();
}
else {
setEditStateAlter();
}
}
void Material::setPhysicalValue(const QString& name, const QString& value)
{
setPhysicalEditState(name);
_physical[name].setValue(value);// may not be a string type
}
void Material::setPhysicalValue(const QString& name, int value)
{
setPhysicalEditState(name);
_physical[name].setInt(value);
}
void Material::setPhysicalValue(const QString& name, double value)
{
setPhysicalEditState(name);
_physical[name].setFloat(value);
}
void Material::setPhysicalValue(const QString& name, const Base::Quantity value)
{
setPhysicalEditState(name);
_physical[name].setQuantity(value);
}
void Material::setAppearanceValue(const QString& name, const QString& value)
{
setAppearanceEditState(name);
_appearance[name].setValue(value);// may not be a string type
}
MaterialProperty& Material::getPhysicalProperty(const QString& name)
{
try {
return _physical.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const MaterialProperty& Material::getPhysicalProperty(const QString& name) const
{
try {
return _physical.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
MaterialProperty& Material::getAppearanceProperty(const QString& name)
{
try {
return _appearance.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const MaterialProperty& Material::getAppearanceProperty(const QString& name) const
{
try {
return _appearance.at(name);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const QVariant Material::getValue(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const
{
try {
return propertyList.at(name).getValue();
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const QString Material::getValueString(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const
{
try {
if (propertyList.at(name).getType() == MaterialValue::Quantity) {
auto value = propertyList.at(name).getValue();
if (value.isNull()) {
return QString();
}
return value.value<Base::Quantity>().getUserString();
}
return propertyList.at(name).getValue().toString();
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}
const QVariant Material::getPhysicalValue(const QString& name) const
{
return getValue(_physical, name);
}
const QString Material::getPhysicalValueString(const QString& name) const
{
return getValueString(_physical, name);
}
const QVariant Material::getAppearanceValue(const QString& name) const
{
return getValue(_appearance, name);
}
const QString Material::getAppearanceValueString(const QString& name) const
{
return getValueString(_appearance, name);
}
bool Material::hasPhysicalProperty(const QString& name) const
{
try {
static_cast<void>(_physical.at(name));
}
catch (std::out_of_range const&) {
return false;
}
return true;
}
bool Material::hasAppearanceProperty(const QString& name) const
{
try {
static_cast<void>(_appearance.at(name));
}
catch (std::out_of_range const&) {
return false;
}
return true;
}
bool Material::hasModel(const QString& uuid) const
{
for (QString modelUUID : _allUuids) {
if (modelUUID == uuid) {
return true;
}
}
return false;
}
bool Material::hasPhysicalModel(const QString& uuid) const
{
if (!hasModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
if (model.getType() == Model::ModelType_Physical) {
return true;
}
}
catch (ModelNotFound const&) {
}
return false;
}
bool Material::hasAppearanceModel(const QString& uuid) const
{
if (!hasModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
if (model.getType() == Model::ModelType_Appearance) {
return true;
}
}
catch (ModelNotFound const&) {
}
return false;
}
bool Material::isPhysicalModelComplete(const QString& uuid) const
{
if (!hasPhysicalModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
const MaterialProperty& property = getPhysicalProperty(propertyName);
if (property.isNull()) {
return false;
}
}
}
catch (ModelNotFound const&) {
return false;
}
return true;
}
bool Material::isAppearanceModelComplete(const QString& uuid) const
{
if (!hasAppearanceModel(uuid)) {
return false;
}
ModelManager manager;
try {
const Model& model = manager.getModel(uuid);
for (auto it = model.begin(); it != model.end(); it++) {
QString propertyName = it->first;
const MaterialProperty& property = getAppearanceProperty(propertyName);
if (property.isNull()) {
return false;
}
}
}
catch (ModelNotFound const&) {
return false;
}
return true;
}
void Material::saveGeneral(QTextStream& stream) const
{
stream << "General:\n";
stream << " UUID: \"" << _uuid << "\"\n";
stream << " Name: \"" << _name << "\"\n";
if (!_authorAndLicense.isEmpty()) {
stream << " AuthorAndLicense: \"" << _authorAndLicense << "\"\n";
}
if (!_description.isEmpty()) {
stream << " Description: \"" << _description << "\"\n";
}
if (!_url.isEmpty()) {
stream << " SourceURL: \"" << _url << "\"\n";
}
if (!_reference.isEmpty()) {
stream << " ReferenceSource: \"" << _reference << "\"\n";
}
}
void Material::saveInherits(QTextStream& stream) const
{
if (!_parentUuid.isEmpty()) {
MaterialManager manager;
stream << "Inherits:\n";
stream << " " << manager.getMaterial(_parentUuid).getName() << ":\n";
stream << " UUID: \"" << _parentUuid << "\"\n";
}
}
void Material::saveModels(QTextStream& stream) const
{
if (!_physical.empty()) {
ModelManager modelManager;
stream << "Models:\n";
for (auto itm = _physicalUuids.begin(); itm != _physicalUuids.end(); itm++) {
auto model = modelManager.getModel(*itm);
stream << " " << model.getName() << ":\n";
stream << " UUID: \"" << model.getUUID() << "\"\n";
for (auto itp = model.begin(); itp != model.end(); itp++) {
QString propertyName = itp->first;
const MaterialProperty& property = getPhysicalProperty(propertyName);
if (!property.isNull()) {
stream << " " << propertyName << ": \""
<< getPhysicalValueString(propertyName) << "\"\n";
}
}
}
}
}
void Material::saveAppearanceModels(QTextStream& stream) const
{
if (!_appearance.empty()) {
ModelManager modelManager;
stream << "AppearanceModels:\n";
for (auto itm = _appearanceUuids.begin(); itm != _appearanceUuids.end(); itm++) {
auto model = modelManager.getModel(*itm);
stream << " " << model.getName() << ":\n";
stream << " UUID: \"" << model.getUUID() << "\"\n";
for (auto itp = model.begin(); itp != model.end(); itp++) {
QString propertyName = itp->first;
const MaterialProperty& property = getAppearanceProperty(propertyName);
if (!property.isNull()) {
stream << " " << propertyName << ": \""
<< getAppearanceValueString(propertyName) << "\"\n";
}
}
}
}
}
void Material::newUuid()
{
_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
}
void Material::save(QTextStream& stream, bool saveAsCopy)
{
Q_UNUSED(saveAsCopy)
stream << "# File created by FreeCAD\n";
saveGeneral(stream);
saveInherits(stream);
saveModels(stream);
saveAppearanceModels(stream);
}
Material& Material::operator=(const Material& other)
{
if (this == &other) {
return *this;
}
_library = other._library;
_directory = other._directory;
_uuid = other._uuid;
_name = other._name;
_authorAndLicense = other._authorAndLicense;
_parentUuid = other._parentUuid;
_description = other._description;
_url = other._url;
_reference = other._reference;
_dereferenced = other._dereferenced;
_tags.clear();
for (auto it = other._tags.begin(); it != other._tags.end(); it++) {
_tags.push_back(*it);
}
_physicalUuids.clear();
for (auto it = other._physicalUuids.begin(); it != other._physicalUuids.end(); it++) {
_physicalUuids.push_back(*it);
}
_appearanceUuids.clear();
for (auto it = other._appearanceUuids.begin(); it != other._appearanceUuids.end(); it++) {
_appearanceUuids.push_back(*it);
}
_allUuids.clear();
for (auto it = other._allUuids.begin(); it != other._allUuids.end(); it++) {
_allUuids.push_back(*it);
}
_physical.clear();
for (auto it = other._physical.begin(); it != other._physical.end(); it++) {
_physical[it->first] = MaterialProperty(it->second);
}
_appearance.clear();
for (auto it = other._appearance.begin(); it != other._appearance.end(); it++) {
_appearance[it->first] = MaterialProperty(it->second);
}
return *this;
}

View File

@@ -0,0 +1,334 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MATERIALS_H
#define MATERIAL_MATERIALS_H
#include <Base/BaseClass.h>
#include <QDir>
#include <QString>
#include <QTextStream>
#include <App/Application.h>
#include "MaterialLibrary.h"
#include "Model.h"
namespace fs = boost::filesystem;
namespace Materials
{
class MaterialsExport MaterialProperty: public ModelProperty
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
public:
MaterialProperty();
explicit MaterialProperty(const ModelProperty& property);
explicit MaterialProperty(const MaterialProperty& property);
virtual ~MaterialProperty();
MaterialValue::ValueType getType(void) const
{
return _valuePtr->getType();
}
const QString getModelUUID(void) const;
const QVariant getValue(void) const;
bool isNull() const
{
return _valuePtr->isNull();
}
MaterialValue* getMaterialValue(void);
const QString getString(void) const;
bool getBoolean(void) const;
int getInt(void) const;
double getFloat(void) const;
const Base::Quantity& getQuantity(void) const;
const QString getURL(void) const;
MaterialProperty& getColumn(int column);
MaterialValue::ValueType getColumnType(int column) const;
QString getColumnUnits(int column) const;
QVariant getColumnNull(int column) const;
void setModelUUID(const QString& uuid);
void setPropertyType(const QString& type) override;
void setValue(const QVariant& value);
void setValue(const QString& value);
void setString(const QString& value);
void setBoolean(bool value);
void setBoolean(int value);
void setBoolean(const QString& value);
void setInt(int value);
void setInt(const QString& value);
void setFloat(double value);
void setFloat(const QString& value);
void setQuantity(const Base::Quantity& value);
void setQuantity(double value, const QString& units);
void setQuantity(const QString& value);
void setURL(const QString& value);
MaterialProperty& operator=(const MaterialProperty& other);
protected:
void setType(const QString& type);
// void setType(MaterialValue::ValueType type) { _valueType = type; }
void addColumn(MaterialProperty& column)
{
_columns.push_back(column);
}
private:
QString _modelUUID;
MaterialValue* _valuePtr;
std::vector<MaterialProperty> _columns;
};
class MaterialsExport Material: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
enum ModelEdit
{
ModelEdit_None, // No change
ModelEdit_Alter,// Existing values are changed
ModelEdit_Extend// New values added
};
Material();
explicit Material(const MaterialLibrary& library,
const QString& directory,
const QString& uuid,
const QString& name);
explicit Material(const Material& other);
virtual ~Material();
const MaterialLibrary& getLibrary() const
{
return _library;
}
const QString getDirectory() const
{
return _directory;
}
const QString getUUID() const
{
return _uuid;
}
const QString getName() const
{
return _name;
}
const QString getAuthorAndLicense() const
{
return _authorAndLicense;
}
const QString getParentUUID() const
{
return _parentUuid;
}
const QString getDescription() const
{
return _description;
}
const QString getURL() const
{
return _url;
}
const QString getReference() const
{
return _reference;
}
ModelEdit getEditState() const
{
return _editState;
}
const std::list<QString>& getTags() const
{
return _tags;
}
const std::vector<QString>* getPhysicalModels() const
{
return &_physicalUuids;
}
const std::vector<QString>* getAppearanceModels() const
{
return &_appearanceUuids;
}
void setLibrary(const MaterialLibrary& library)
{
_library = library;
}
void setDirectory(const QString& directory)
{
Base::Console().Log("Materials::setDirectory(%s)\n", directory.toStdString().c_str());
_directory = directory;
}
void setUUID(const QString& uuid)
{
_uuid = uuid;
}
void setName(const QString& name)
{
_name = name;
}
void setAuthorAndLicense(const QString& authorAndLicense)
{
_authorAndLicense = authorAndLicense;
}
void setParentUUID(const QString& uuid)
{
_parentUuid = uuid;
}
void setDescription(const QString& description)
{
_description = description;
}
void setURL(const QString& url)
{
_url = url;
}
void setReference(const QString& reference)
{
_reference = reference;
}
void setEditState(ModelEdit newState);
void setEditStateAlter()
{
setEditState(ModelEdit_Alter);
}
void setEditStateExtend()
{
setEditState(ModelEdit_Extend);
}
void setPhysicalEditState(const QString& name);
void setAppearanceEditState(const QString& name);
void resetEditState()
{
_editState = ModelEdit_None;
}
void addTag(const QString& tag)
{
Q_UNUSED(tag);
}
void removeTag(const QString& tag)
{
Q_UNUSED(tag);
}
void addPhysical(const QString& uuid);
void addAppearance(const QString& uuid);
void newUuid();
void setPhysicalValue(const QString& name, const QString& value);
void setPhysicalValue(const QString& name, int value);
void setPhysicalValue(const QString& name, double value);
void setPhysicalValue(const QString& name, const Base::Quantity value);
void setAppearanceValue(const QString& name, const QString& value);
MaterialProperty& getPhysicalProperty(const QString& name);
const MaterialProperty& getPhysicalProperty(const QString& name) const;
MaterialProperty& getAppearanceProperty(const QString& name);
const MaterialProperty& getAppearanceProperty(const QString& name) const;
const QVariant getPhysicalValue(const QString& name) const;
const QString getPhysicalValueString(const QString& name) const;
const QVariant getAppearanceValue(const QString& name) const;
const QString getAppearanceValueString(const QString& name) const;
bool hasPhysicalProperty(const QString& name) const;
bool hasAppearanceProperty(const QString& name) const;
// Test if the model is defined, and if values are provided for all properties
bool hasModel(const QString& uuid) const;
bool hasPhysicalModel(const QString& uuid) const;
bool hasAppearanceModel(const QString& uuid) const;
bool isModelComplete(const QString& uuid) const
{
return isPhysicalModelComplete(uuid) || isAppearanceModelComplete(uuid);
}
bool isPhysicalModelComplete(const QString& uuid) const;
bool isAppearanceModelComplete(const QString& uuid) const;
const std::map<QString, MaterialProperty>& getPhysicalProperties() const
{
return _physical;
}
const std::map<QString, MaterialProperty>& getAppearanceProperties() const
{
return _appearance;
}
bool getDereferenced() const
{
return _dereferenced;
}
void markDereferenced()
{
_dereferenced = true;
}
void save(QTextStream& stream, bool saveAsCopy);
Material& operator=(const Material& other);
protected:
void addModel(const QString& uuid);
const QVariant getValue(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const;
const QString getValueString(const std::map<QString, MaterialProperty>& propertyList,
const QString& name) const;
void saveGeneral(QTextStream& stream) const;
void saveInherits(QTextStream& stream) const;
void saveModels(QTextStream& stream) const;
void saveAppearanceModels(QTextStream& stream) const;
private:
MaterialLibrary _library;
QString _directory;
QString _uuid;
QString _name;
QString _authorAndLicense;
QString _parentUuid;
QString _description;
QString _url;
QString _reference;
std::list<QString> _tags;
std::vector<QString> _physicalUuids;
std::vector<QString> _appearanceUuids;
std::vector<QString> _allUuids;// Includes inherited models
std::map<QString, MaterialProperty> _physical;
std::map<QString, MaterialProperty> _appearance;
bool _dereferenced;
ModelEdit _editState;
};
}// namespace Materials
Q_DECLARE_METATYPE(Materials::Material*)
#endif// MATERIAL_MATERIALS_H

View File

@@ -0,0 +1,116 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include "Exceptions.h"
#include "Model.h"
#include "ModelLibrary.h"
#include <string>
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::ModelProperty, Base::BaseClass)
ModelProperty::ModelProperty()
{}
ModelProperty::ModelProperty(const QString& name,
const QString& type,
const QString& units,
const QString& url,
const QString& description)
: _name(name)
, _propertyType(type)
, _units(units)
, _url(url)
, _description(description)
{}
ModelProperty::ModelProperty(const ModelProperty& other)
: _name(other._name)
, _propertyType(other._propertyType)
, _units(other._units)
, _url(other._url)
, _description(other._description)
, _inheritance(other._inheritance)
{
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
}
ModelProperty& ModelProperty::operator=(const ModelProperty& other)
{
if (this == &other) {
return *this;
}
_name = other._name;
_propertyType = other._propertyType;
_units = other._units;
_url = other._url;
_description = other._description;
_inheritance = other._inheritance;
_columns.clear();
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
_columns.push_back(*it);
}
return *this;
}
TYPESYSTEM_SOURCE(Materials::Model, Base::BaseClass)
Model::Model()
{}
Model::Model(const ModelLibrary& library,
ModelType type,
const QString& name,
const QString& directory,
const QString& uuid,
const QString& description,
const QString& url,
const QString& doi)
: _library(library)
, _type(type)
, _name(name)
, _directory(directory)
, _uuid(uuid)
, _description(description)
, _url(url)
, _doi(doi)
{}
ModelProperty& Model::operator[](const QString& key)
{
try {
return _properties.at(key);
}
catch (std::out_of_range const&) {
throw PropertyNotFound();
}
}

View File

@@ -0,0 +1,297 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODEL_H
#define MATERIAL_MODEL_H
#include <Base/BaseClass.h>
#include <Base/Quantity.h>
#include <QDir>
#include <QString>
#include "MaterialValue.h"
#include "ModelLibrary.h"
namespace Materials
{
class MaterialsExport ModelProperty: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
ModelProperty();
explicit ModelProperty(const QString& name,
const QString& type,
const QString& units,
const QString& url,
const QString& description);
explicit ModelProperty(const ModelProperty& other);
virtual ~ModelProperty() = default;
const QString getName() const
{
return _name;
}
const QString getPropertyType() const
{
return _propertyType;
}
const QString getUnits() const
{
return _units;
}
const QString getURL() const
{
return _url;
}
const QString getDescription() const
{
return _description;
}
const QString getInheritance() const
{
return _inheritance;
}
bool isInherited() const
{
return (_inheritance.length() > 0);
}
void setName(const QString& name)
{
_name = name;
}
virtual void setPropertyType(const QString& type)
{
_propertyType = type;
}
void setUnits(const QString& units)
{
_units = units;
}
void setURL(const QString& url)
{
_url = url;
}
void setDescription(const QString& description)
{
_description = description;
}
void setInheritance(const QString& uuid)
{
_inheritance = uuid;
}
void addColumn(ModelProperty& column)
{
_columns.push_back(column);
}
const std::vector<ModelProperty>& getColumns() const
{
return _columns;
}
int columns() const
{
return _columns.size();
}
ModelProperty& operator=(const ModelProperty& other);
private:
QString _name;
QString _propertyType;
QString _units;
QString _url;
QString _description;
QString _inheritance;
std::vector<ModelProperty> _columns;
};
class MaterialsExport Model: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
enum ModelType
{
ModelType_Physical,
ModelType_Appearance
};
Model();
explicit Model(const ModelLibrary& library,
ModelType type,
const QString& name,
const QString& directory,
const QString& uuid,
const QString& description,
const QString& url,
const QString& doi);
virtual ~Model() = default;
const ModelLibrary& getLibrary() const
{
return _library;
}
const QString getBase() const
{
return (_type == ModelType_Physical) ? QString::fromStdString("Model")
: QString::fromStdString("AppearanceModel");
}
const QString getName() const
{
return _name;
}
ModelType getType() const
{
return _type;
}
const QString getDirectory() const
{
return _directory;
}
const QString getDirectoryPath() const
{
return QDir(_directory).absolutePath();
}
const QString getRelativePath() const
{
return QDir(_directory).relativeFilePath(QDir(_directory).absolutePath());
}
const QString getUUID() const
{
return _uuid;
}
const QString getDescription() const
{
return _description;
}
const QString getURL() const
{
return _url;
}
const QString getDOI() const
{
return _doi;
}
void setLibrary(const ModelLibrary& library)
{
_library = library;
}
void setType(ModelType type)
{
_type = type;
}
void setName(const QString& name)
{
_name = name;
}
void setDirectory(const QString& directory)
{
_directory = directory;
}
void setUUID(const QString& uuid)
{
_uuid = uuid;
}
void setDescription(const QString& description)
{
_description = description;
}
void setURL(const QString& url)
{
_url = url;
}
void setDOI(const QString& doi)
{
_doi = doi;
}
void addInheritance(const QString& uuid)
{
_inheritedUuids.push_back(uuid);
}
const std::vector<QString>& getInheritance() const
{
return _inheritedUuids;
}
bool operator==(const Model& m) const
{
return _uuid == m._uuid;
}
bool operator!=(const Model& m) const
{
return !operator==(m);
}
ModelProperty& operator[](const QString& key);
void addProperty(ModelProperty& property)
{
_properties[property.getName()] = property;
}
using iterator = typename std::map<QString, ModelProperty>::iterator;
using const_iterator = typename std::map<QString, ModelProperty>::const_iterator;
iterator begin()
{
return _properties.begin();
}
const_iterator begin() const noexcept
{
return _properties.begin();
}
iterator end() noexcept
{
return _properties.end();
}
const_iterator end() const noexcept
{
return _properties.end();
}
const_iterator cbegin() const noexcept
{
return _properties.cbegin();
}
const_iterator cend() const noexcept
{
return _properties.cend();
}
private:
ModelLibrary _library;
ModelType _type;
QString _name;
QString _directory;
QString _uuid;
QString _description;
QString _url;
QString _doi;
std::vector<QString> _inheritedUuids;
std::map<QString, ModelProperty> _properties;
};
}// namespace Materials
#endif// MATERIAL_MODEL_H

View File

@@ -0,0 +1,114 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <string>
#include <App/Application.h>
#include "Exceptions.h"
#include "Model.h"
#include "ModelLibrary.h"
using namespace Materials;
TYPESYSTEM_SOURCE(Materials::LibraryBase, Base::BaseClass)
LibraryBase::LibraryBase(const QString& libraryName, const QString& dir, const QString& icon)
: _name(libraryName)
, _directory(QDir::cleanPath(dir))
, _iconPath(icon)
{}
LibraryBase::LibraryBase()
{}
bool LibraryBase::operator==(const LibraryBase& library) const
{
return (_name == library._name) && (_directory == library._directory);
}
QString LibraryBase::getLocalPath(const QString& path) const
{
QString filePath = getDirectoryPath();
QString cleanPath = QDir::cleanPath(path);
QString prefix = QString::fromStdString("/") + getName();
if (cleanPath.startsWith(prefix)) {
// Remove the library name from the path
filePath += cleanPath.right(cleanPath.length() - prefix.length());
}
else {
filePath += cleanPath;
}
return filePath;
}
QString LibraryBase::getRelativePath(const QString& path) const
{
QString filePath;
QString cleanPath = QDir::cleanPath(path);
QString prefix = QString::fromStdString("/") + getName();
if (cleanPath.startsWith(prefix)) {
// Remove the library name from the path
filePath = cleanPath.right(cleanPath.length() - prefix.length());
}
else {
filePath = cleanPath;
}
prefix = getDirectoryPath();
if (filePath.startsWith(prefix)) {
// Remove the library root from the path
filePath = filePath.right(filePath.length() - prefix.length());
}
// Remove any leading '/'
if (filePath.startsWith(QString::fromStdString("/"))) {
filePath.remove(0, 1);
}
return filePath;
}
TYPESYSTEM_SOURCE(Materials::ModelLibrary, LibraryBase)
ModelLibrary::ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon)
: LibraryBase(libraryName, dir, icon)
{}
ModelLibrary::ModelLibrary()
{}
Model* ModelLibrary::addModel(const Model& model, const QString& path)
{
QString filePath = getRelativePath(path);
Model* newModel = new Model(model);
newModel->setLibrary(*this);
newModel->setDirectory(filePath);
return newModel;
}

View File

@@ -0,0 +1,100 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELLIBRARY_H
#define MATERIAL_MODELLIBRARY_H
#include <Base/BaseClass.h>
#include <Base/Quantity.h>
#include <QDir>
#include <QString>
#include "MaterialValue.h"
namespace Materials
{
class Model;
class MaterialsExport LibraryBase: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
LibraryBase();
explicit LibraryBase(const QString& libraryName, const QString& dir, const QString& icon);
virtual ~LibraryBase() = default;
const QString getName() const
{
return _name;
}
const QString getDirectory() const
{
return _directory;
}
const QString getDirectoryPath() const
{
return QDir(_directory).absolutePath();
}
const QString getIconPath() const
{
return _iconPath;
}
bool operator==(const LibraryBase& library) const;
bool operator!=(const LibraryBase& library) const
{
return !operator==(library);
}
QString getLocalPath(const QString& path) const;
QString getRelativePath(const QString& path) const;
private:
QString _name;
QString _directory;
QString _iconPath;
};
class MaterialsExport ModelLibrary: public LibraryBase
{
TYPESYSTEM_HEADER();
public:
ModelLibrary();
explicit ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon);
virtual ~ModelLibrary() = default;
bool operator==(const ModelLibrary& library) const
{
return LibraryBase::operator==(library);
}
bool operator!=(const ModelLibrary& library) const
{
return !operator==(library);
}
Model* addModel(const Model& model, const QString& path);
};
}// namespace Materials
#endif// MATERIAL_MODELLIBRARY_H

View File

@@ -0,0 +1,417 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <QString>
#endif
#include <App/Application.h>
#include <Base/Interpreter.h>
#include <QDirIterator>
#include <QFileInfo>
#include "Model.h"
#include "ModelLoader.h"
#include "ModelManager.h"
using namespace Materials;
ModelEntry::ModelEntry(const ModelLibrary& library,
const QString& baseName,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData)
: _library(library)
, _base(baseName)
, _name(modelName)
, _directory(dir)
, _uuid(modelUuid)
, _model(modelData)
, _dereferenced(false)
{}
std::map<QString, ModelEntry*>* ModelLoader::_modelEntryMap = nullptr;
ModelLoader::ModelLoader(std::map<QString, Model*>* modelMap, std::list<ModelLibrary*>* libraryList)
: _modelMap(modelMap)
, _libraryList(libraryList)
{
loadLibraries();
}
void ModelLoader::addLibrary(ModelLibrary* model)
{
_libraryList->push_back(model);
}
const QString ModelLoader::getUUIDFromPath(const QString& path)
{
QFile file(path);
if (!file.exists()) {
throw ModelNotFound();
}
try {
YAML::Node yamlroot = YAML::LoadFile(path.toStdString());
std::string base = "Model";
if (yamlroot["AppearanceModel"]) {
base = "AppearanceModel";
}
const QString uuid = QString::fromStdString(yamlroot[base]["UUID"].as<std::string>());
return uuid;
}
catch (YAML::Exception& ex) {
throw ModelNotFound();
}
}
ModelEntry* ModelLoader::getModelFromPath(const ModelLibrary& library, const QString& path) const
{
QFile file(path);
if (!file.exists()) {
throw ModelNotFound();
}
YAML::Node yamlroot;
std::string base = "Model";
std::string uuid;
std::string name;
try {
yamlroot = YAML::LoadFile(path.toStdString());
if (yamlroot["AppearanceModel"]) {
base = "AppearanceModel";
}
uuid = yamlroot[base]["UUID"].as<std::string>();
name = yamlroot[base]["Name"].as<std::string>();
}
catch (YAML::Exception const&) {
throw InvalidModel();
}
ModelEntry* model = new ModelEntry(library,
QString::fromStdString(base),
QString::fromStdString(name),
path,
QString::fromStdString(uuid),
yamlroot);
return model;
}
void ModelLoader::showYaml(const YAML::Node& yaml) const
{
std::stringstream out;
out << yaml;
std::string logData = out.str();
Base::Console().Log("%s\n", logData.c_str());
}
void ModelLoader::dereference(const QString& uuid,
ModelEntry* parent,
const ModelEntry* child,
std::map<std::pair<QString, QString>, QString>* inheritances)
{
auto parentPtr = parent->getModelPtr();
auto parentBase = parent->getBase().toStdString();
auto childYaml = child->getModel();
auto childBase = child->getBase().toStdString();
std::set<QString> exclude;
exclude.insert(QString::fromStdString("Name"));
exclude.insert(QString::fromStdString("UUID"));
exclude.insert(QString::fromStdString("URL"));
exclude.insert(QString::fromStdString("Description"));
exclude.insert(QString::fromStdString("DOI"));
exclude.insert(QString::fromStdString("Inherits"));
auto parentProperties = (*parentPtr)[parentBase];
auto childProperties = childYaml[childBase];
for (auto it = childProperties.begin(); it != childProperties.end(); it++) {
std::string name = it->first.as<std::string>();
if (exclude.count(QString::fromStdString(name)) == 0) {
// showYaml(it->second);
if (!parentProperties[name]) {
parentProperties[name] = it->second;
// parentProperties[name]["Inherits"] = childYaml[childBase]["UUID"];
(*inheritances)[std::pair<QString, QString>(uuid, QString::fromStdString(name))] =
yamlValue(childYaml[childBase], "UUID", "");
}
}
}
// showYaml(*parentPtr);
}
void ModelLoader::dereference(ModelEntry* model,
std::map<std::pair<QString, QString>, QString>* inheritances)
{
// Avoid recursion
if (model->getDereferenced()) {
return;
}
auto yamlModel = model->getModel();
auto base = model->getBase().toStdString();
if (yamlModel[base]["Inherits"]) {
auto inherits = yamlModel[base]["Inherits"];
for (auto it = inherits.begin(); it != inherits.end(); it++) {
QString nodeName = QString::fromStdString((*it)["UUID"].as<std::string>());
// This requires that all models have already been loaded undereferenced
try {
const ModelEntry* child = (*_modelEntryMap)[nodeName];
dereference(model->getUUID(), model, child, inheritances);
}
catch (const std::out_of_range& oor) {
Base::Console().Log("Unable to find '%s' in model map\n",
nodeName.toStdString().c_str());
}
}
}
model->markDereferenced();
}
QString ModelLoader::yamlValue(const YAML::Node& node,
const std::string& key,
const std::string& defaultValue)
{
if (node[key]) {
return QString::fromStdString(node[key].as<std::string>());
}
return QString::fromStdString(defaultValue);
}
void ModelLoader::addToTree(ModelEntry* model,
std::map<std::pair<QString, QString>, QString>* inheritances)
{
std::set<QString> exclude;
exclude.insert(QString::fromStdString("Name"));
exclude.insert(QString::fromStdString("UUID"));
exclude.insert(QString::fromStdString("URL"));
exclude.insert(QString::fromStdString("Description"));
exclude.insert(QString::fromStdString("DOI"));
exclude.insert(QString::fromStdString("Inherits"));
auto yamlModel = model->getModel();
auto library = model->getLibrary();
auto base = model->getBase().toStdString();
auto name = model->getName();
auto directory = model->getDirectory();
auto uuid = model->getUUID();
QString version = yamlValue(yamlModel["General"], "Version", "");
QString description = yamlValue(yamlModel[base], "Description", "");
QString url = yamlValue(yamlModel[base], "URL", "");
QString doi = yamlValue(yamlModel[base], "DOI", "");
Model::ModelType type =
(base == "Model") ? Model::ModelType_Physical : Model::ModelType_Appearance;
Model* finalModel = new Model(library, type, name, directory, uuid, description, url, doi);
// Add inheritance list
if (yamlModel[base]["Inherits"]) {
auto inherits = yamlModel[base]["Inherits"];
for (auto it = inherits.begin(); it != inherits.end(); it++) {
QString nodeName = QString::fromStdString((*it)["UUID"].as<std::string>());
finalModel->addInheritance(nodeName);
}
}
// Add property list
auto yamlProperties = yamlModel[base];
for (auto it = yamlProperties.begin(); it != yamlProperties.end(); it++) {
std::string propName = it->first.as<std::string>();
if (exclude.count(QString::fromStdString(propName)) == 0) {
// showYaml(it->second);
auto yamlProp = yamlProperties[propName];
auto propType = yamlValue(yamlProp, "Type", "");
auto propUnits = yamlValue(yamlProp, "Units", "");
auto propURL = yamlValue(yamlProp, "URL", "");
auto propDescription = yamlValue(yamlProp, "Description", "");
// auto inherits = yamlValue(yamlProp, "Inherits", "");
ModelProperty property(QString::fromStdString(propName),
propType,
propUnits,
propURL,
propDescription);
if (propType == QString::fromStdString("2DArray")
|| propType == QString::fromStdString("3DArray")) {
Base::Console().Log("Reading columns\n");
// Read the columns
auto cols = yamlProp["Columns"];
for (auto col : cols) {
std::string colName = col.first.as<std::string>();
Base::Console().Log("\tColumns '%s'\n", colName.c_str());
auto colProp = cols[colName];
auto colPropType = yamlValue(colProp, "Type", "");
auto colPropUnits = yamlValue(colProp, "Units", "");
auto colPropURL = yamlValue(colProp, "URL", "");
auto colPropDescription = yamlValue(colProp, "Description", "");
ModelProperty colProperty(QString::fromStdString(colName),
colPropType,
colPropUnits,
colPropURL,
colPropDescription);
property.addColumn(colProperty);
}
}
auto key = std::pair<QString, QString>(uuid, QString::fromStdString(propName));
if (inheritances->count(key) > 0) {
property.setInheritance((*inheritances)[key]);
}
finalModel->addProperty(property);
}
}
(*_modelMap)[uuid] = library.addModel(*finalModel, directory);
}
void ModelLoader::loadLibrary(const ModelLibrary& library)
{
if (_modelEntryMap == nullptr) {
_modelEntryMap = new std::map<QString, ModelEntry*>();
}
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
while (it.hasNext()) {
auto pathname = it.next();
QFileInfo file(pathname);
if (file.isFile()) {
if (file.suffix().toStdString() == "yml") {
QString libraryName = file.baseName();
try {
auto model = getModelFromPath(library, file.canonicalFilePath());
(*_modelEntryMap)[model->getUUID()] = model;
// showYaml(model->getModel());
}
catch (InvalidModel const&) {
Base::Console().Log("Invalid model '%s'\n", pathname.toStdString().c_str());
}
}
}
}
std::map<std::pair<QString, QString>, QString>* inheritances =
new std::map<std::pair<QString, QString>, QString>();
for (auto it = _modelEntryMap->begin(); it != _modelEntryMap->end(); it++) {
dereference(it->second, inheritances);
}
for (auto it = _modelEntryMap->begin(); it != _modelEntryMap->end(); it++) {
addToTree(it->second, inheritances);
}
// delete inheritances;
}
void ModelLoader::loadLibraries(void)
{
getModelLibraries();
if (_libraryList) {
for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) {
loadLibrary(**it);
}
}
}
void ModelLoader::getModelLibraries()
{
auto param = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources");
bool useBuiltInMaterials = param->GetBool("UseBuiltInMaterials", true);
bool useMatFromModules = param->GetBool("UseMaterialsFromWorkbenches", true);
bool useMatFromConfigDir = param->GetBool("UseMaterialsFromConfigDir", true);
bool useMatFromCustomDir = param->GetBool("UseMaterialsFromCustomDir", true);
if (useBuiltInMaterials) {
QString resourceDir = QString::fromStdString(App::Application::getResourceDir()
+ "/Mod/Material/Resources/Models");
auto libData = new ModelLibrary(QString::fromStdString("System"),
resourceDir,
QString::fromStdString(":/icons/freecad.svg"));
_libraryList->push_back(libData);
}
if (useMatFromModules) {
auto moduleParam = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Material/Resources/Modules");
for (auto& group : moduleParam->GetGroups()) {
// auto module = moduleParam->GetGroup(group->GetGroupName());
auto moduleName = QString::fromStdString(group->GetGroupName());
auto modelDir = QString::fromStdString(group->GetASCII("ModuleModelDir", ""));
auto modelIcon = QString::fromStdString(group->GetASCII("ModuleIcon", ""));
if (modelDir.length() > 0) {
QDir dir(modelDir);
if (dir.exists()) {
auto libData = new ModelLibrary(moduleName, modelDir, modelIcon);
_libraryList->push_back(libData);
}
}
}
}
if (useMatFromConfigDir) {
QString resourceDir =
QString::fromStdString(App::Application::getUserAppDataDir() + "/Models");
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData =
new ModelLibrary(QString::fromStdString("User"),
resourceDir,
QString::fromStdString(":/icons/preferences-general.svg"));
_libraryList->push_back(libData);
}
}
}
if (useMatFromCustomDir) {
QString resourceDir = QString::fromStdString(param->GetASCII("CustomMaterialsDir", ""));
if (!resourceDir.isEmpty()) {
QDir materialDir(resourceDir);
if (materialDir.exists()) {
auto libData = new ModelLibrary(QString::fromStdString("Custom"),
resourceDir,
QString::fromStdString(":/icons/user.svg"));
_libraryList->push_back(libData);
}
}
}
}

View File

@@ -0,0 +1,130 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELLOADER_H
#define MATERIAL_MODELLOADER_H
#include <QDir>
#include <QString>
#include <yaml-cpp/yaml.h>
#include "Model.h"
namespace Materials
{
class ModelEntry
{
public:
explicit ModelEntry(const ModelLibrary& library,
const QString& baseName,
const QString& modelName,
const QString& dir,
const QString& modelUuid,
const YAML::Node& modelData);
virtual ~ModelEntry() = default;
const ModelLibrary& getLibrary() const
{
return _library;
}
const QString getBase() const
{
return _base;
}
const QString getName() const
{
return _name;
}
const QString getDirectory() const
{
return _directory;
}
const QString getUUID() const
{
return _uuid;
}
const YAML::Node& getModel() const
{
return _model;
}
YAML::Node* getModelPtr()
{
return &_model;
}
bool getDereferenced() const
{
return _dereferenced;
}
void markDereferenced()
{
_dereferenced = true;
}
private:
ModelEntry();
ModelLibrary _library;
QString _base;
QString _name;
QString _directory;
QString _uuid;
YAML::Node _model;
bool _dereferenced;
};
class ModelLoader
{
public:
explicit ModelLoader(std::map<QString, Model*>* modelMap,
std::list<ModelLibrary*>* libraryList);
virtual ~ModelLoader() = default;
static const QString getUUIDFromPath(const QString& path);
private:
ModelLoader();
void getModelLibraries();
QString
yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue);
void addToTree(ModelEntry* model, std::map<std::pair<QString, QString>, QString>* inheritances);
void showYaml(const YAML::Node& yaml) const;
void dereference(const QString& uuid,
ModelEntry* parent,
const ModelEntry* child,
std::map<std::pair<QString, QString>, QString>* inheritances);
void dereference(ModelEntry* model,
std::map<std::pair<QString, QString>, QString>* inheritances);
ModelEntry* getModelFromPath(const ModelLibrary& library, const QString& path) const;
void addLibrary(ModelLibrary* model);
void loadLibrary(const ModelLibrary& library);
void loadLibraries(void);
static std::map<QString, ModelEntry*>* _modelEntryMap;
std::map<QString, Model*>* _modelMap;
std::list<ModelLibrary*>* _libraryList;
};
}// namespace Materials
#endif// MATERIAL_MODELLOADER_H

View File

@@ -0,0 +1,172 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#endif
#include <QMutexLocker>
#include <Base/Console.h>
#include "Model.h"
#include "ModelLoader.h"
#include "ModelManager.h"
using namespace Materials;
std::list<ModelLibrary*>* ModelManager::_libraryList = nullptr;
std::map<QString, Model*>* ModelManager::_modelMap = nullptr;
QMutex ModelManager::_mutex;
TYPESYSTEM_SOURCE(Materials::ModelManager, Base::BaseClass)
ModelManager::ModelManager()
{
initLibraries();
}
void ModelManager::initLibraries()
{
QMutexLocker locker(&_mutex);
if (_modelMap == nullptr) {
_modelMap = new std::map<QString, Model*>();
if (_libraryList == nullptr) {
_libraryList = new std::list<ModelLibrary*>();
}
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
}
}
bool ModelManager::isModel(const fs::path& p)
{
// if (!fs::is_regular_file(p))
// return false;
// check file extension
if (p.extension() == ".yml") {
return true;
}
return false;
}
void ModelManager::refresh()
{
_modelMap->clear();
_libraryList->clear();
// Load the libraries
ModelLoader loader(_modelMap, _libraryList);
}
const Model& ModelManager::getModel(const QString& uuid) const
{
try {
if (_modelMap == nullptr) {
throw Uninitialized();
}
return *(_modelMap->at(uuid));
}
catch (std::out_of_range const&) {
throw ModelNotFound();
}
}
const Model& ModelManager::getModelByPath(const QString& path) const
{
const QString& uuid = ModelLoader::getUUIDFromPath(path);
const Model& model = getModel(uuid);
return model;
}
const Model& ModelManager::getModelByPath(const QString& path, const QString& libraryPath) const
{
QDir modelDir(QDir::cleanPath(libraryPath + QString::fromStdString("/") + path));
QString absPath = modelDir.absolutePath();
return getModelByPath(absPath);
}
bool ModelManager::passFilter(ModelFilter filter, Model::ModelType modelType) const
{
switch (filter) {
case ModelFilter_None:
return true;
case ModelFilter_Physical:
return (modelType == Model::ModelType_Physical);
case ModelFilter_Appearance:
return (modelType == Model::ModelType_Appearance);
}
return false;
}
std::map<QString, ModelTreeNode*>* ModelManager::getModelTree(const ModelLibrary& library,
ModelFilter filter)
{
std::map<QString, ModelTreeNode*>* modelTree = new std::map<QString, ModelTreeNode*>();
for (auto it = _modelMap->begin(); it != _modelMap->end(); it++) {
auto filename = it->first;
auto model = it->second;
if (model->getLibrary() == library && passFilter(filter, model->getType())) {
fs::path path = model->getDirectory().toStdString();
Base::Console().Log("Relative path '%s'\n\t", path.string().c_str());
// Start at the root
std::map<QString, ModelTreeNode*>* node = modelTree;
for (auto itp = path.begin(); itp != path.end(); itp++) {
if (isModel(itp->string())) {
ModelTreeNode* child = new ModelTreeNode();
child->setData(model);
(*node)[QString::fromStdString(itp->string())] = child;
}
else {
// Add the folder only if it's not already there
QString folderName = QString::fromStdString(itp->string());
std::map<QString, ModelTreeNode*>* mapPtr;
if (node->count(QString::fromStdString(itp->string())) == 0) {
mapPtr = new std::map<QString, ModelTreeNode*>();
ModelTreeNode* child = new ModelTreeNode();
child->setFolder(mapPtr);
(*node)[QString::fromStdString(itp->string())] = child;
node = mapPtr;
}
else {
node = (*node)[QString::fromStdString(itp->string())]->getFolder();
}
}
Base::Console().Log("'%s' ", itp->string().c_str());
}
Base::Console().Log("\n");
}
}
return modelTree;
}

View File

@@ -0,0 +1,85 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELMANAGER_H
#define MATERIAL_MODELMANAGER_H
#include <QMutex>
#include <boost/filesystem.hpp>
#include "Exceptions.h"
#include "FolderTree.h"
#include "Model.h"
namespace fs = boost::filesystem;
namespace Materials
{
typedef FolderTreeNode<Model> ModelTreeNode;
class MaterialsExport ModelManager: public Base::BaseClass
{
TYPESYSTEM_HEADER();
public:
enum ModelFilter
{
ModelFilter_None,
ModelFilter_Physical,
ModelFilter_Appearance
};
ModelManager();
virtual ~ModelManager() = default;
void refresh();
std::list<ModelLibrary*>* getModelLibraries()
{
return _libraryList;
}
std::map<QString, Model*>* getModels()
{
return _modelMap;
}
std::map<QString, ModelTreeNode*>* getModelTree(const ModelLibrary& library,
ModelFilter filter = ModelFilter_None);
const Model& getModel(const QString& uuid) const;
const Model& getModelByPath(const QString& path) const;
const Model& getModelByPath(const QString& path, const QString& libraryPath) const;
static bool isModel(const fs::path& p);
bool passFilter(ModelFilter filter, Model::ModelType modelType) const;
private:
static void initLibraries();
static std::list<ModelLibrary*>* _libraryList;
static std::map<QString, Model*>* _modelMap;
static QMutex _mutex;
};
}// namespace Materials
#endif// MATERIAL_MODELMANAGER_H

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="ModelManagerPy"
Twin="ModelManager"
TwinPointer="ModelManager"
Include="Mod/Material/App/ModelManager.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material model descriptions.</UserDocu>
</Documentation>
<Methode Name="getModel">
<Documentation>
<UserDocu>Get a model object by specifying its UUID</UserDocu>
</Documentation>
</Methode>
<Methode Name="getModelByPath">
<Documentation>
<UserDocu>Get a model object by specifying its path</UserDocu>
</Documentation>
</Methode>
<Attribute Name="ModelLibraries" ReadOnly="true">
<Documentation>
<UserDocu>List of model libraries.</UserDocu>
</Documentation>
<Parameter Name="ModelLibraries" Type="List"/>
</Attribute>
<Attribute Name="Models" ReadOnly="true">
<Documentation>
<UserDocu>List of model libraries.</UserDocu>
</Documentation>
<Parameter Name="Models" Type="Dict"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,163 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "ModelManager.h"
#include "ModelManagerPy.h"
#include "ModelPy.h"
#include "ModelManagerPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string ModelManagerPy::representation() const
{
std::stringstream str;
str << "<ModelManager object at " << getModelManagerPtr() << ">";
return str.str();
}
PyObject* ModelManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new ModelManagerPy(new ModelManager());
}
// constructor method
int ModelManagerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
PyObject* ModelManagerPy::getModel(PyObject* args)
{
char* uuid;
if (!PyArg_ParseTuple(args, "s", &uuid)) {
return nullptr;
}
try {
const Model model = getModelManagerPtr()->getModel(QString::fromStdString(uuid));
return new ModelPy(new Model(model));
}
catch (ModelNotFound const&) {
QString error = QString::fromStdString("Model not found:\n");
std::map<QString, Model*>* _modelMap = getModelManagerPtr()->getModels();
error += QString::fromStdString("ModelMap:\n");
for (auto itp = _modelMap->begin(); itp != _modelMap->end(); itp++) {
error += QString::fromStdString("\t_modelMap[") + itp->first
+ QString::fromStdString("] = '") + itp->second->getName()
+ QString::fromStdString("'\n");
}
error += QString::fromStdString("\tuuid = '") + QString::fromStdString(uuid)
+ QString::fromStdString("'\n");
PyErr_SetString(PyExc_LookupError, error.toStdString().c_str());
return nullptr;
}
catch (Uninitialized const&) {
PyErr_SetString(PyExc_LookupError, "Uninitialized model list");
return nullptr;
}
}
PyObject* ModelManagerPy::getModelByPath(PyObject* args)
{
char* path;
char* lib = "";
if (!PyArg_ParseTuple(args, "s|s", &path, &lib)) {
return nullptr;
}
std::string libPath(lib);
if (libPath.length() > 0) {
try {
const Model& model =
getModelManagerPtr()->getModelByPath(QString::fromStdString(path),
QString::fromStdString(libPath));
return new ModelPy(new Model(model));
}
catch (ModelNotFound const&) {
PyErr_SetString(PyExc_LookupError, "Model not found");
return nullptr;
}
}
try {
const Model& model = getModelManagerPtr()->getModelByPath(QString::fromStdString(path));
return new ModelPy(new Model(model));
}
catch (ModelNotFound const&) {
PyErr_SetString(PyExc_LookupError, "Model not found");
return nullptr;
}
}
Py::List ModelManagerPy::getModelLibraries() const
{
std::list<ModelLibrary*>* libraries = getModelManagerPtr()->getModelLibraries();
Py::List list;
for (auto it = libraries->begin(); it != libraries->end(); it++) {
ModelLibrary* lib = *it;
Py::Tuple libTuple(3);
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
list.append(libTuple);
}
return list;
}
Py::Dict ModelManagerPy::getModels() const
{
std::map<QString, Model*>* models = getModelManagerPtr()->getModels();
Py::Dict dict;
for (auto it = models->begin(); it != models->end(); it++) {
QString key = it->first;
Model* model = it->second;
PyObject* modelPy = new ModelPy(new Model(*model));
dict.setItem(Py::String(key.toStdString()), Py::Object(modelPy, true));
}
return dict;
}
PyObject* ModelManagerPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int ModelManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="ModelPropertyPy"
Twin="ModelProperty"
TwinPointer="ModelProperty"
Include="Mod/Material/App/Model.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material property descriptions.</UserDocu>
</Documentation>
<!-- <Methode Name="mirror">
<Documentation>
<UserDocu>Performs the symmetrical transformation of this geometric object</UserDocu>
</Documentation>
</Methode> -->
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>Property name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Type" ReadOnly="true">
<Documentation>
<UserDocu>Property type.</UserDocu>
</Documentation>
<Parameter Name="Type" Type="String"/>
</Attribute>
<Attribute Name="Units" ReadOnly="true">
<Documentation>
<UserDocu>Property units category.</UserDocu>
</Documentation>
<Parameter Name="Units" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Documentation>
<UserDocu>URL to a detailed description of the property.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>Property description.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,101 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "Model.h"
#include "ModelPropertyPy.h"
#include "ModelPropertyPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string ModelPropertyPy::representation() const
{
ModelPropertyPy::PointerType ptr = getModelPropertyPtr();
std::stringstream str;
str << "Property [Name=(";
str << ptr->getName().toStdString();
str << "), Type=(";
str << ptr->getPropertyType().toStdString();
str << "), Units=(";
str << ptr->getUnits().toStdString();
str << "), URL=(";
str << ptr->getURL().toStdString();
str << "), Description=(";
str << ptr->getDescription().toStdString();
str << ")]";
return str.str();
}
PyObject* ModelPropertyPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new ModelPropertyPy(new ModelProperty());
}
// constructor method
int ModelPropertyPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String ModelPropertyPy::getName() const
{
return Py::String(getModelPropertyPtr()->getName().toStdString());
}
Py::String ModelPropertyPy::getType() const
{
return Py::String(getModelPropertyPtr()->getPropertyType().toStdString());
}
Py::String ModelPropertyPy::getUnits() const
{
return Py::String(getModelPropertyPtr()->getUnits().toStdString());
}
Py::String ModelPropertyPy::getURL() const
{
return Py::String(getModelPropertyPtr()->getURL().toStdString());
}
Py::String ModelPropertyPy::getDescription() const
{
return Py::String(getModelPropertyPtr()->getDescription().toStdString());
}
PyObject* ModelPropertyPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int ModelPropertyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
<PythonExport
Father="BaseClassPy"
Name="ModelPy"
Twin="Model"
TwinPointer="Model"
Include="Mod/Material/App/Model.h"
Namespace="Materials"
FatherInclude="Base/BaseClassPy.h"
FatherNamespace="Base"
Constructor="true"
Delete="true">
<Documentation>
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
<UserDocu>Material model descriptions.</UserDocu>
</Documentation>
<Attribute Name="LibraryName" ReadOnly="true">
<Documentation>
<UserDocu>Model library name.</UserDocu>
</Documentation>
<Parameter Name="LibraryName" Type="String"/>
</Attribute>
<Attribute Name="LibraryRoot" ReadOnly="true">
<Documentation>
<UserDocu>Model library path.</UserDocu>
</Documentation>
<Parameter Name="LibraryRoot" Type="String"/>
</Attribute>
<Attribute Name="LibraryIcon" ReadOnly="true">
<Documentation>
<UserDocu>Model icon path.</UserDocu>
</Documentation>
<Parameter Name="LibraryIcon" Type="String"/>
</Attribute>
<Attribute Name="Name" ReadOnly="true">
<Documentation>
<UserDocu>Model name.</UserDocu>
</Documentation>
<Parameter Name="Name" Type="String"/>
</Attribute>
<Attribute Name="Directory" ReadOnly="true">
<Documentation>
<UserDocu>Model directory.</UserDocu>
</Documentation>
<Parameter Name="Directory" Type="String"/>
</Attribute>
<Attribute Name="UUID" ReadOnly="true">
<Documentation>
<UserDocu>Unique model identifier.</UserDocu>
</Documentation>
<Parameter Name="UUID" Type="String"/>
</Attribute>
<Attribute Name="Description" ReadOnly="true">
<Documentation>
<UserDocu>Description of the model.</UserDocu>
</Documentation>
<Parameter Name="Description" Type="String"/>
</Attribute>
<Attribute Name="URL" ReadOnly="true">
<Documentation>
<UserDocu>URL to a detailed description of the model.</UserDocu>
</Documentation>
<Parameter Name="URL" Type="String"/>
</Attribute>
<Attribute Name="DOI" ReadOnly="true">
<Documentation>
<UserDocu>Digital Object Identifier (see https://doi.org/)</UserDocu>
</Documentation>
<Parameter Name="DOI" Type="String"/>
</Attribute>
<Attribute Name="Inherited" ReadOnly="true">
<Documentation>
<UserDocu>List of inherited models identified by UUID.</UserDocu>
</Documentation>
<Parameter Name="Inherited" Type="List"/>
</Attribute>
<Attribute Name="Properties" ReadOnly="true">
<Documentation>
<UserDocu>Dictionary of model properties.</UserDocu>
</Documentation>
<Parameter Name="Properties" Type="Dict"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -0,0 +1,172 @@
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
#include <boost/uuid/uuid_io.hpp>
#endif
#include "Model.h"
#include "ModelPropertyPy.h"
#include "ModelPy.h"
#include "ModelPy.cpp"
using namespace Materials;
// returns a string which represents the object e.g. when printed in python
std::string ModelPy::representation() const
{
ModelPy::PointerType ptr = getModelPtr();
std::stringstream str;
str << "Property [Name=(";
str << ptr->getName().toStdString();
str << "), UUID=(";
str << ptr->getUUID().toStdString();
str << "), Library Name=(";
str << ptr->getLibrary().getName().toStdString();
str << "), Library Root=(";
str << ptr->getLibrary().getDirectoryPath().toStdString();
str << "), Library Icon=(";
str << ptr->getLibrary().getIconPath().toStdString();
str << "), Directory=(";
str << ptr->getDirectory().toStdString();
str << "), URL=(";
str << ptr->getURL().toStdString();
str << "), DOI=(";
str << ptr->getDOI().toStdString();
str << "), Description=(";
str << ptr->getDescription().toStdString();
str << "), Inherits=[";
const std::vector<QString>& inherited = getModelPtr()->getInheritance();
for (auto it = inherited.begin(); it != inherited.end(); it++) {
QString uuid = *it;
if (it != inherited.begin()) {
str << "), UUID=(";
}
else {
str << "UUID=(";
}
str << uuid.toStdString() << ")";
}
str << "]]";
return str.str();
}
PyObject* ModelPy::PyMake(struct _typeobject*, PyObject*, PyObject*)// Python wrapper
{
// never create such objects with the constructor
return new ModelPy(new Model());
}
// constructor method
int ModelPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
{
return 0;
}
Py::String ModelPy::getLibraryName() const
{
return Py::String(getModelPtr()->getLibrary().getName().toStdString());
}
Py::String ModelPy::getLibraryRoot() const
{
return Py::String(getModelPtr()->getLibrary().getDirectoryPath().toStdString());
}
Py::String ModelPy::getLibraryIcon() const
{
return Py::String(getModelPtr()->getLibrary().getIconPath().toStdString());
}
Py::String ModelPy::getName() const
{
return Py::String(getModelPtr()->getName().toStdString());
}
Py::String ModelPy::getDirectory() const
{
return Py::String(getModelPtr()->getDirectoryPath().toStdString());
}
Py::String ModelPy::getUUID() const
{
return Py::String(getModelPtr()->getUUID().toStdString());
}
Py::String ModelPy::getDescription() const
{
return Py::String(getModelPtr()->getDescription().toStdString());
}
Py::String ModelPy::getURL() const
{
return Py::String(getModelPtr()->getURL().toStdString());
}
Py::String ModelPy::getDOI() const
{
return Py::String(getModelPtr()->getDOI().toStdString());
}
Py::List ModelPy::getInherited() const
{
const std::vector<QString>& inherited = getModelPtr()->getInheritance();
Py::List list;
for (auto it = inherited.begin(); it != inherited.end(); it++) {
QString uuid = *it;
list.append(Py::String(uuid.toStdString()));
}
return list;
}
Py::Dict ModelPy::getProperties() const
{
// std::map<std::string, Model*> *models = getModelPtr()->getModels();
Py::Dict dict;
for (auto it = getModelPtr()->begin(); it != getModelPtr()->end(); it++) {
QString key = it->first;
ModelProperty& modelProperty = it->second;
PyObject* modelPropertyPy = new ModelPropertyPy(new ModelProperty(modelProperty));
dict.setItem(Py::String(key.toStdString()), Py::Object(modelPropertyPy, true));
}
return dict;
}
PyObject* ModelPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
}
int ModelPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
}

View File

@@ -0,0 +1,73 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_MODELUUIDS_H
#define MATERIAL_MODELUUIDS_H
namespace Materials
{
// UUIDs for predefined material models
static const QString ModelUUID_Legacy_Father =
QString::fromStdString("9cdda8b6-b606-4778-8f13-3934d8668e67");
static const QString ModelUUID_Legacy_MaterialStandard =
QString::fromStdString("1e2c0088-904a-4537-925f-64064c07d700");
static const QString ModelUUID_Mechanical_Density =
QString::fromStdString("454661e5-265b-4320-8e6f-fcf6223ac3af");
static const QString ModelUUID_Mechanical_IsotropicLinearElastic =
QString::fromStdString("f6f9e48c-b116-4e82-ad7f-3659a9219c50");
static const QString ModelUUID_Mechanical_LinearElastic =
QString::fromStdString("7b561d1d-fb9b-44f6-9da9-56a4f74d7536");
static const QString ModelUUID_Mechanical_OgdenYld2004p18 =
QString::fromStdString("3ef9e427-cc25-43f7-817f-79ff0d49625f");
static const QString ModelUUID_Mechanical_OrthotropicLinearElastic =
QString::fromStdString("b19ccc6b-a431-418e-91c2-0ac8c649d146");
static const QString ModelUUID_Fluid_Default =
QString::fromStdString("1ae66d8c-1ba1-4211-ad12-b9917573b202");
static const QString ModelUUID_Thermal_Default =
QString::fromStdString("9959d007-a970-4ea7-bae4-3eb1b8b883c7");
static const QString ModelUUID_Electromagnetic_Default =
QString::fromStdString("b2eb5f48-74b3-4193-9fbb-948674f427f3");
static const QString ModelUUID_Architectural_Default =
QString::fromStdString("32439c3b-262f-4b7b-99a8-f7f44e5894c8");
static const QString ModelUUID_Costs_Default =
QString::fromStdString("881df808-8726-4c2e-be38-688bb6cce466");
static const QString ModelUUID_Rendering_Basic =
QString::fromStdString("f006c7e4-35b7-43d5-bbf9-c5d572309e6e");
static const QString ModelUUID_Rendering_Texture =
QString::fromStdString("bbdcc65b-67ca-489c-bd5c-a36e33d1c160");
static const QString ModelUUID_Rendering_Advanced =
QString::fromStdString("c880f092-cdae-43d6-a24b-55e884aacbbf");
static const QString ModelUUID_Rendering_Vector =
QString::fromStdString("fdf5a80e-de50-4157-b2e5-b6e5f88b680e");
}// namespace Materials
#endif// MATERIAL_MODELUUIDS_H

View File

@@ -0,0 +1,24 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"

View File

@@ -0,0 +1,67 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATGUI_PRECOMPILED_H
#define MATGUI_PRECOMPILED_H
#include <FCConfig.h>
#include <Mod/Material/MaterialGlobal.h>
// point at which warnings of overly long specifiers disabled (needed for VC6)
#ifdef _MSC_VER
# pragma warning( disable : 4251 )
# pragma warning( disable : 4503 )
# pragma warning( disable : 4786 ) // specifier longer then 255 chars
# pragma warning( disable : 4273 )
#endif
#ifdef FC_OS_WIN32
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#endif
#ifdef _PreComp_
// standard
#include <cfloat>
#include <cmath>
// STL
#include <algorithm>
#include <map>
#include <sstream>
#include <string>
#include <vector>
// Qt
#include <QtGlobal>
// Boost
#include <boost/regex.hpp>
#include <boost/algorithm/string/predicate.hpp>
#endif //_PreComp_
#endif // MATGUI_PRECOMPILED_H

View File

@@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef MATERIAL_TRIM_H
#define MATERIAL_TRIM_H
#include <string>
namespace Materials
{
// trim from start (in place)
static inline void ltrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(),
s.rend(),
[](unsigned char ch) {
return !std::isspace(ch);
})
.base(),
s.end());
}
// trim from both ends (in place)
static inline void trim(std::string& s)
{
rtrim(s);
ltrim(s);
}
// trim from start (copying)
static inline std::string ltrim_copy(std::string s)
{
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrim_copy(std::string s)
{
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trim_copy(std::string s)
{
trim(s);
return s;
}
}// namespace Materials
#endif// MATERIAL_TRIM_H