Material: Material API fixes

Corrects an issue in the API where a new material may not have a UUID.
Corrected the test case to reflect the changes and better document the
process.

Added a test case for material filters.
This commit is contained in:
David Carter
2024-05-13 22:41:54 -04:00
committed by Chris Hennes
parent b231bbb0ca
commit ed01d5cffa
13 changed files with 404 additions and 25 deletions

View File

@@ -3,6 +3,7 @@ target_sources(
Material_tests_run
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/TestMaterialCards.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TestMaterialFilter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TestMaterialProperties.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TestMaterials.cpp
${CMAKE_CURRENT_SOURCE_DIR}/TestMaterialValue.cpp
@@ -13,3 +14,25 @@ target_sources(
target_include_directories(Material_tests_run PUBLIC
${QtCore_INCLUDE_DIRS}
)
set(MaterialTestData_Files
Materials/TestAcrylicLegacy.FCMat
Materials/TestAluminumAppearance.FCMat
Materials/TestAluminumMixed.FCMat
Materials/TestAluminumPhysical.FCMat
Materials/TestBrassAppearance.FCMat
)
ADD_CUSTOM_TARGET(MaterialTestData ALL
SOURCES ${MaterialTestData_Files}
)
fc_target_copy_resource(MaterialTestData
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/tests
${MaterialTestData_Files})
# INSTALL(
# FILES ${MaterialTest_Files}
# DESTINATION Mod/Material/materialtests
# )

View File

@@ -0,0 +1,13 @@
; Acrylic
; Automatically generated by the Rocket Workbench
; information about the content of such cards can be found on the wiki:
; https://www.freecadweb.org/wiki/Material
[General]
Name = TestAcrylicLegacy
Description = Acrylic
KindOfMaterial = Solid
[Mechanical]
Density = 1190.0 kg/m^3
Hardness = 10

View File

@@ -0,0 +1,17 @@
---
# File created by ConvertFCMat.py
General:
UUID: "3c6d0407-66b3-48ea-a2e8-ee843edf0311"
Author: "David Carter"
License: "GPL-2.0-or-later"
Name: "TestAluminumAppearance"
Description: "Defines the Aluminum appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.3000, 0.3000, 0.3000, 1.0)"
DiffuseColor: "(0.3000, 0.3000, 0.3000, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.0900"
SpecularColor: "(0.3000, 0.3000, 0.3000, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,33 @@
---
# File created by ConvertFCMat.py
General:
UUID: "5f546608-fcbb-40db-98d7-d8e104eb33ce"
Author: "M. Münch"
License: "LGPL-2.0-or-later"
Name: "TestAluminumMixed"
Inherits:
Aluminum:
UUID: "3c6d0407-66b3-48ea-a2e8-ee843edf0311"
Models:
Father:
UUID: '9cdda8b6-b606-4778-8f13-3934d8668e67'
Father: "Metal"
MaterialStandard:
UUID: '1e2c0088-904a-4537-925f-64064c07d700'
KindOfMaterial: "Aluminium"
MaterialNumber: "3.3535.26"
StandardCode: "DIN 1725"
LinearElastic:
UUID: '7b561d1d-fb9b-44f6-9da9-56a4f74d7536'
Density: "2700 kg/m^3"
PoissonRatio: "0.3"
ShearModulus: "27000 MPa"
UltimateStrain: "5"
UltimateTensileStrength: "250 MPa"
YieldStrength: "180 MPa"
YoungsModulus: "70000 MPa"
Thermal:
UUID: '9959d007-a970-4ea7-bae4-3eb1b8b883c7'
SpecificHeat: "900 J/kg/K"
ThermalConductivity: "150 W/m/K"
ThermalExpansionCoefficient: "23 µm/m/K"

View File

@@ -0,0 +1,30 @@
---
# File created by ConvertFCMat.py
General:
UUID: "a8e60089-550d-4370-8e7e-1734db12a3a9"
Author: "M. Münch"
License: "LGPL-2.0-or-later"
Name: "TestAluminumPhysical"
Models:
Father:
UUID: '9cdda8b6-b606-4778-8f13-3934d8668e67'
Father: "Metal"
MaterialStandard:
UUID: '1e2c0088-904a-4537-925f-64064c07d700'
KindOfMaterial: "Aluminium"
MaterialNumber: "3.3535.26"
StandardCode: "DIN 1725"
LinearElastic:
UUID: '7b561d1d-fb9b-44f6-9da9-56a4f74d7536'
Density: "2700 kg/m^3"
PoissonRatio: "0.3"
ShearModulus: "27000 MPa"
# UltimateStrain: "5"
UltimateTensileStrength: "250 MPa"
YieldStrength: "180 MPa"
YoungsModulus: "70000 MPa"
Thermal:
UUID: '9959d007-a970-4ea7-bae4-3eb1b8b883c7'
SpecificHeat: "900 J/kg/K"
ThermalConductivity: "150 W/m/K"
ThermalExpansionCoefficient: "23 µm/m/K"

View File

@@ -0,0 +1,17 @@
---
# File created by ConvertFCMat.py
General:
UUID: "fff3d5c8-98c3-4ee2-8fe5-7e17403c48fcc"
Author: "David Carter"
License: "GPL-2.0-or-later"
Name: "TestBrassAppearance"
Description: "Defines the Brass appearance properties"
AppearanceModels:
BasicRendering:
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
AmbientColor: "(0.3294, 0.2235, 0.0275, 1.0)"
DiffuseColor: "(0.7804, 0.5686, 0.1137, 1.0)"
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
Shininess: "0.2179"
SpecularColor: "(0.9922, 0.9412, 0.8078, 1.0)"
Transparency: "0.0"

View File

@@ -0,0 +1,244 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
**************************************************************************/
#include "gtest/gtest.h"
#include <Mod/Material/App/PreCompiled.h>
#ifndef _PreComp_
#endif
#include <QMetaType>
#include <QString>
#include <App/Application.h>
#include <Base/Quantity.h>
#include <Gui/MetaTypes.h>
#include <src/App/InitApplication.h>
#include <Mod/Material/App/MaterialLibrary.h>
#include <Mod/Material/App/MaterialManager.h>
#include <Mod/Material/App/MaterialValue.h>
#include <Mod/Material/App/Model.h>
#include <Mod/Material/App/ModelManager.h>
#include <Mod/Material/App/ModelUuids.h>
// clang-format off
class TestMaterialFilter : public ::testing::Test {
protected:
static void SetUpTestSuite() {
if (App::Application::GetARGC() == 0) {
tests::initApplication();
}
}
void SetUp() override {
_modelManager = new Materials::ModelManager();
_materialManager = new Materials::MaterialManager();
// Use our test files as a custom directory
ParameterGrp::handle hGrp =
App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Material/Resources");
_customDir = hGrp->GetASCII("CustomMaterialsDir", "");
_useBuiltInDir = hGrp->GetBool("UseBuiltInMaterials", true);
_useWorkbenchDir = hGrp->GetBool("UseMaterialsFromWorkbenches", true);
_useUserDir = hGrp->GetBool("UseMaterialsFromConfigDir", true);
_useCustomDir = hGrp->GetBool("UseMaterialsFromCustomDir", false);
std::string testPath = App::Application::getHomePath() + "/tests/Materials/";
hGrp->SetASCII("CustomMaterialsDir", testPath);
hGrp->SetBool("UseBuiltInMaterials", false);
hGrp->SetBool("UseMaterialsFromWorkbenches", false);
hGrp->SetBool("UseMaterialsFromConfigDir", false);
hGrp->SetBool("UseMaterialsFromCustomDir", true);
_materialManager->refresh();
_library = _materialManager->getLibrary(QLatin1String("Custom"));
}
void TearDown() override {
ParameterGrp::handle hGrp =
App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Material/Resources");
// Restore preferences
hGrp->SetASCII("CustomMaterialsDir", _customDir);
hGrp->SetBool("UseBuiltInMaterials", _useBuiltInDir);
hGrp->SetBool("UseMaterialsFromWorkbenches", _useWorkbenchDir);
hGrp->SetBool("UseMaterialsFromConfigDir", _useUserDir);
hGrp->SetBool("UseMaterialsFromCustomDir", _useCustomDir);
_materialManager->refresh();
}
Materials::ModelManager* _modelManager;
Materials::MaterialManager* _materialManager;
std::shared_ptr<Materials::MaterialLibrary> _library;
QString _testMaterialUUID;
std::string _customDir;
bool _useBuiltInDir;
bool _useWorkbenchDir;
bool _useUserDir;
bool _useCustomDir;
const char* UUIDAcrylicLegacy = ""; // This can't be known until it is loaded
const char* UUIDAluminumAppearance = "3c6d0407-66b3-48ea-a2e8-ee843edf0311";
const char* UUIDAluminumMixed = "5f546608-fcbb-40db-98d7-d8e104eb33ce";
const char* UUIDAluminumPhysical = "a8e60089-550d-4370-8e7e-1734db12a3a9";
const char* UUIDBrassAppearance = "fff3d5c8-98c3-4ee2-8fe5-7e17403c48fcc";
};
TEST_F(TestMaterialFilter, TestFilters)
{
ASSERT_NE(_modelManager, nullptr);
// First check that our materials are loading
auto material = _materialManager->getMaterial(QString::fromLatin1(UUIDAluminumAppearance));
ASSERT_TRUE(material);
ASSERT_EQ(material->getName(), QString::fromLatin1("TestAluminumAppearance"));
ASSERT_EQ(material->getUUID(), QString::fromLatin1(UUIDAluminumAppearance));
material = _materialManager->getMaterial(QString::fromLatin1(UUIDAluminumMixed));
ASSERT_TRUE(material);
ASSERT_EQ(material->getName(), QString::fromLatin1("TestAluminumMixed"));
ASSERT_EQ(material->getUUID(), QString::fromLatin1(UUIDAluminumMixed));
material = _materialManager->getMaterial(QString::fromLatin1(UUIDAluminumPhysical));
ASSERT_TRUE(material);
ASSERT_EQ(material->getName(), QString::fromLatin1("TestAluminumPhysical"));
ASSERT_EQ(material->getUUID(), QString::fromLatin1(UUIDAluminumPhysical));
material = _materialManager->getMaterial(QString::fromLatin1(UUIDBrassAppearance));
ASSERT_TRUE(material);
ASSERT_EQ(material->getName(), QString::fromLatin1("TestBrassAppearance"));
ASSERT_EQ(material->getUUID(), QString::fromLatin1(UUIDBrassAppearance));
material = _materialManager->getMaterialByPath(QString::fromLatin1("TestAcrylicLegacy.FCMat"),
QString::fromLatin1("Custom"));
ASSERT_TRUE(material);
ASSERT_EQ(material->getName(), QString::fromLatin1("TestAcrylicLegacy"));
ASSERT_EQ(material->getUUID().size(), 36); // We don't know the UUID
// Create an empty filter
auto filter = std::make_shared<Materials::MaterialFilter>();
Materials::MaterialFilterOptions options;
ASSERT_TRUE(_library);
auto tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 4);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 5);
// Create a basic rendering filter
filter->setName(QLatin1String("Basic Appearance"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 3);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 3);
// Create an advanced rendering filter
filter->clear();
filter->setName(QLatin1String("Advanced Appearance"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Advanced);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 0);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 0);
// Create a Density filter
filter->clear();
filter->setName(QLatin1String("Density"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_Density);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 2);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 3);
// Create a Hardness filter
filter->clear();
filter->setName(QLatin1String("Hardness"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_Hardness);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 0);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 0);
// Create a Density and Basic Rendering filter
filter->clear();
filter->setName(QLatin1String("Density and Basic Rendering"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_Density);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 1);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 1);
// Create a Linear Elastic filter
filter->clear();
filter->setName(QLatin1String("Linear Elastic"));
filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Mechanical_LinearElastic);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 0);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 0);
filter->clear();
filter->setName(QLatin1String("Linear Elastic"));
filter->addRequired(Materials::ModelUUIDs::ModelUUID_Mechanical_LinearElastic);
options.setIncludeLegacy(false);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 2);
options.setIncludeLegacy(true);
tree = _materialManager->getMaterialTree(_library, filter, options);
ASSERT_EQ(tree->size(), 2);
}

View File

@@ -0,0 +1,104 @@
# **************************************************************************
# Copyright (c) 2023 David Carter <dcarter@davidcarter.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 Library 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 *
# **************************************************************************
"""
Test module for FreeCAD material cards and APIs
"""
import os
import unittest
import FreeCAD
import Materials
parseQuantity = FreeCAD.Units.parseQuantity
UUIDAcrylicLegacy = "" # This can't be known until it is loaded
UUIDAluminumAppearance = "3c6d0407-66b3-48ea-a2e8-ee843edf0311"
UUIDAluminumMixed = "5f546608-fcbb-40db-98d7-d8e104eb33ce"
UUIDAluminumPhysical = "a8e60089-550d-4370-8e7e-1734db12a3a9"
UUIDBrassAppearance = "fff3d5c8-98c3-4ee2-8fe5-7e17403c48fcc"
class MaterialFilterTestCases(unittest.TestCase):
"""
Test class for FreeCAD material cards and APIs
"""
def setUp(self):
"""Setup function to initialize test data"""
self.ModelManager = Materials.ModelManager()
self.MaterialManager = Materials.MaterialManager()
self.uuids = Materials.UUIDs()
# Use our test files as a custom directory
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Resources")
self.customDir = param.GetString("CustomMaterialsDir", "")
self.useBuiltInDir = param.GetBool("UseBuiltInMaterials", False)
self.useWorkbenchDir = param.GetBool("UseMaterialsFromWorkbenches", False)
self.useUserDir = param.GetBool("UseMaterialsFromConfigDir", False)
self.useCustomDir = param.GetBool("UseMaterialsFromCustomDir", False)
filePath = os.path.dirname(__file__) + os.sep
testPath = filePath + "Materials"
param.SetString("CustomMaterialsDir", testPath)
param.SetBool("UseBuiltInMaterials", False)
param.SetBool("UseMaterialsFromWorkbenches", False)
param.SetBool("UseMaterialsFromConfigDir", False)
param.SetBool("UseMaterialsFromCustomDir", True)
self.MaterialManager.refresh()
def tearDown(self):
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Resources")
# Restore preferences
param.SetString("CustomMaterialsDir", self.customDir)
param.SetBool("UseBuiltInMaterials", self.useBuiltInDir)
param.SetBool("UseMaterialsFromWorkbenches", self.useWorkbenchDir)
param.SetBool("UseMaterialsFromConfigDir", self.useUserDir)
param.SetBool("UseMaterialsFromCustomDir", self.useCustomDir)
self.MaterialManager.refresh()
def testFilter(self):
"""Test that our filter returns the correct materials"""
# First check that our materials are loading
material = self.MaterialManager.getMaterial(UUIDAluminumAppearance)
self.assertIsNotNone(material)
self.assertEqual(material.Name, "TestAluminumAppearance")
self.assertEqual(material.UUID, UUIDAluminumAppearance)
material = self.MaterialManager.getMaterial(UUIDAluminumMixed)
self.assertIsNotNone(material)
self.assertEqual(material.Name, "TestAluminumMixed")
self.assertEqual(material.UUID, UUIDAluminumMixed)
material = self.MaterialManager.getMaterial(UUIDAluminumPhysical)
self.assertIsNotNone(material)
self.assertEqual(material.Name, "TestAluminumPhysical")
self.assertEqual(material.UUID, UUIDAluminumPhysical)
material = self.MaterialManager.getMaterial(UUIDBrassAppearance)
self.assertIsNotNone(material)
self.assertEqual(material.Name, "TestBrassAppearance")
self.assertEqual(material.UUID, UUIDBrassAppearance)