Material: Compatibility with older FCMat files
Provides compatibility loading older files outside the context of a library. Older material files were loaded by specifying a path. The new material system used the path to associated the material with a library, which may not be appropriate for legacy files. This change allows the use of materials outside of a library. Additionally, legacy files often have name/value pairs not part of the standard list of properties. Since these were unable to be mapped to a model property they were ignored. Materials now maintain a legacy map to hold properties not associated with a property model. These properties are considered transient and will not be saved. It is not intended for this feature to be used as a generic container for properties not mapped to an appropriate model. Fixes #13302
This commit is contained in:
committed by
Yorik van Havre
parent
0056038ff4
commit
f950a0c086
@@ -1017,6 +1017,22 @@ void MaterialConfigLoader::addMechanical(const QMap<QString, QString>& fcmat,
|
||||
setPhysicalValue(finalModel, "Stiffness", stiffness);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addLegacy(const QMap<QString, QString>& fcmat,
|
||||
const std::shared_ptr<Material>& finalModel)
|
||||
{
|
||||
for (auto const& legacy : fcmat.keys()) {
|
||||
auto name = legacy;
|
||||
int last = name.lastIndexOf(QLatin1String("/"));
|
||||
if (last > 0) {
|
||||
name = name.mid(last + 1);
|
||||
}
|
||||
|
||||
if (!finalModel->hasNonLegacyProperty(name)) {
|
||||
setLegacyValue(finalModel, name.toStdString(), fcmat[legacy]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Material>
|
||||
MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>& library,
|
||||
const QString& path)
|
||||
@@ -1081,6 +1097,7 @@ MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr<MaterialLibrary>
|
||||
addRendering(fcmat, finalModel);
|
||||
addVectorRendering(fcmat, finalModel);
|
||||
addRenderWB(fcmat, finalModel);
|
||||
addLegacy(fcmat, finalModel);
|
||||
|
||||
return finalModel;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,14 @@ private:
|
||||
finalModel->setAppearanceValue(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
static void setLegacyValue(const std::shared_ptr<Material>& finalModel,
|
||||
const std::string& name,
|
||||
const QString& value)
|
||||
{
|
||||
if (!value.isEmpty()) {
|
||||
finalModel->setLegacyValue(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
static bool isTexture(const QString& value)
|
||||
{
|
||||
@@ -147,6 +155,8 @@ private:
|
||||
const std::shared_ptr<Material>& finalModel);
|
||||
static void addRenderWB(QMap<QString, QString>& fcmat,
|
||||
const std::shared_ptr<Material>& finalModel);
|
||||
static void addLegacy(const QMap<QString, QString>& fcmat,
|
||||
const std::shared_ptr<Material>& finalModel);
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
@@ -196,6 +196,17 @@ std::shared_ptr<Material> MaterialManager::getMaterialByPath(const QString& path
|
||||
}
|
||||
}
|
||||
|
||||
// Older workbenches may try files outside the context of a library
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (MaterialConfigLoader::isConfigStyle(path)) {
|
||||
auto material = MaterialConfigLoader::getMaterialFromPath(nullptr, path);
|
||||
|
||||
return material;
|
||||
}
|
||||
}
|
||||
|
||||
throw MaterialNotFound();
|
||||
}
|
||||
|
||||
|
||||
@@ -141,6 +141,11 @@
|
||||
<UserDocu>Check if the material implements the appearance property with the given name</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="hasLegacyProperties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Returns true of there are legacy properties</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Properties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>deprecated -- Dictionary of all material properties.</UserDocu>
|
||||
@@ -159,6 +164,12 @@
|
||||
</Documentation>
|
||||
<Parameter Name="AppearanceProperties" Type="Dict"/>
|
||||
</Attribute>
|
||||
<Attribute Name="LegacyProperties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>deprecated -- Dictionary of material legacy properties.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LegacyProperties" Type="Dict"/>
|
||||
</Attribute>
|
||||
<Methode Name="getPhysicalValue" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get the value associated with the property</UserDocu>
|
||||
|
||||
@@ -280,6 +280,16 @@ PyObject* MaterialPy::hasAppearanceProperty(PyObject* args)
|
||||
return PyBool_FromLong(hasProperty ? 1 : 0);
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::hasLegacyProperties(PyObject* args)
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasProperty = getMaterialPtr()->hasLegacyProperties();
|
||||
return PyBool_FromLong(hasProperty ? 1 : 0);
|
||||
}
|
||||
|
||||
Py::Dict MaterialPy::getProperties() const
|
||||
{
|
||||
Py::Dict dict;
|
||||
@@ -319,6 +329,16 @@ Py::Dict MaterialPy::getProperties() const
|
||||
}
|
||||
}
|
||||
|
||||
auto legacy = getMaterialPtr()->getLegacyProperties();
|
||||
for (auto& it : legacy) {
|
||||
auto key = it.first;
|
||||
auto value = it.second;
|
||||
|
||||
if (!value.isEmpty()) {
|
||||
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
@@ -358,6 +378,23 @@ Py::Dict MaterialPy::getAppearanceProperties() const
|
||||
return dict;
|
||||
}
|
||||
|
||||
Py::Dict MaterialPy::getLegacyProperties() const
|
||||
{
|
||||
Py::Dict dict;
|
||||
|
||||
auto legacy = getMaterialPtr()->getLegacyProperties();
|
||||
for (auto& it : legacy) {
|
||||
auto key = it.first;
|
||||
auto value = it.second;
|
||||
|
||||
if (!value.isEmpty()) {
|
||||
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static Py::List getList(const QVariant& value)
|
||||
{
|
||||
auto listValue = value.value<QList<QVariant>>();
|
||||
|
||||
@@ -499,6 +499,9 @@ Material::Material(const Material& other)
|
||||
MaterialProperty prop(it.second);
|
||||
_appearance[it.first] = std::make_shared<MaterialProperty>(prop);
|
||||
}
|
||||
for (auto& it : other._legacy) {
|
||||
_legacy[it.first] = it.second;
|
||||
}
|
||||
}
|
||||
|
||||
QString Material::getAuthorAndLicense() const
|
||||
@@ -890,6 +893,13 @@ void Material::setAppearanceValue(const QString& name,
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setLegacyValue(const QString& name, const QString& value)
|
||||
{
|
||||
setEditStateAlter();
|
||||
|
||||
_legacy[name] = value;
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialProperty> Material::getPhysicalProperty(const QString& name)
|
||||
{
|
||||
try {
|
||||
@@ -1047,6 +1057,19 @@ bool Material::hasAppearanceProperty(const QString& name) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Material::hasNonLegacyProperty(const QString& name) const
|
||||
{
|
||||
if (hasPhysicalProperty(name) || hasAppearanceProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Material::hasLegacyProperties() const
|
||||
{
|
||||
return !_legacy.empty();
|
||||
}
|
||||
|
||||
bool Material::isInherited(const QString& uuid) const
|
||||
{
|
||||
if (_physicalUuids.contains(uuid)) {
|
||||
@@ -1464,6 +1487,10 @@ Material& Material::operator=(const Material& other)
|
||||
MaterialProperty prop(it.second);
|
||||
_appearance[it.first] = std::make_shared<MaterialProperty>(prop);
|
||||
}
|
||||
_legacy.clear();
|
||||
for (auto& it : other._legacy) {
|
||||
_legacy[it.first] = it.second;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -299,6 +299,15 @@ public:
|
||||
void setAppearanceValue(const QString& name, const std::shared_ptr<MaterialValue>& value);
|
||||
void setAppearanceValue(const QString& name, const std::shared_ptr<QList<QVariant>>& value);
|
||||
|
||||
/*
|
||||
* Legacy values are thosed contained in old format files that don't fit in the new
|
||||
* property format. It should not be used as a catch all for defining a property with
|
||||
* no model.
|
||||
*
|
||||
* These values are transient and will not be saved.
|
||||
*/
|
||||
void setLegacyValue(const QString& name, const QString& value);
|
||||
|
||||
std::shared_ptr<MaterialProperty> getPhysicalProperty(const QString& name);
|
||||
std::shared_ptr<MaterialProperty> getPhysicalProperty(const QString& name) const;
|
||||
std::shared_ptr<MaterialProperty> getAppearanceProperty(const QString& name);
|
||||
@@ -313,6 +322,9 @@ public:
|
||||
QString getAppearanceValueString(const QString& name) const;
|
||||
bool hasPhysicalProperty(const QString& name) const;
|
||||
bool hasAppearanceProperty(const QString& name) const;
|
||||
bool hasNonLegacyProperty(const QString& name) const;
|
||||
bool hasLegacyProperty(const QString& name) const;
|
||||
bool hasLegacyProperties() const;
|
||||
|
||||
// Test if the model is defined, and if values are provided for all properties
|
||||
bool hasModel(const QString& uuid) const;
|
||||
@@ -334,6 +346,10 @@ public:
|
||||
{
|
||||
return _appearance;
|
||||
}
|
||||
std::map<QString, QString>& getLegacyProperties()
|
||||
{
|
||||
return _legacy;
|
||||
}
|
||||
|
||||
QString getModelByName(const QString& name) const;
|
||||
|
||||
@@ -438,6 +454,7 @@ private:
|
||||
QSet<QString> _allUuids; // Includes inherited models
|
||||
std::map<QString, std::shared_ptr<MaterialProperty>> _physical;
|
||||
std::map<QString, std::shared_ptr<MaterialProperty>> _appearance;
|
||||
std::map<QString, QString> _legacy;
|
||||
bool _dereferenced;
|
||||
bool _oldFormat;
|
||||
ModelEdit _editState;
|
||||
|
||||
@@ -71,6 +71,8 @@ class MaterialTestCases(unittest.TestCase):
|
||||
self.assertFalse(steel.isPhysicalModelComplete(self.uuids.LinearElastic))
|
||||
self.assertTrue(steel.isAppearanceModelComplete(self.uuids.BasicRendering))
|
||||
|
||||
self.assertFalse(steel.hasLegacyProperties())
|
||||
|
||||
self.assertTrue(steel.hasPhysicalProperty("Density"))
|
||||
self.assertTrue(steel.hasPhysicalProperty("BulkModulus"))
|
||||
self.assertTrue(steel.hasPhysicalProperty("PoissonRatio"))
|
||||
@@ -118,6 +120,9 @@ class MaterialTestCases(unittest.TestCase):
|
||||
self.assertIn("SpecularColor", properties)
|
||||
self.assertIn("Transparency", properties)
|
||||
|
||||
properties = steel.LegacyProperties
|
||||
self.assertEqual(len(properties), 0)
|
||||
|
||||
properties = steel.Properties
|
||||
self.assertIn("Density", properties)
|
||||
self.assertNotIn("BulkModulus", properties)
|
||||
|
||||
Reference in New Issue
Block a user