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
477 lines
15 KiB
C++
477 lines
15 KiB
C++
/***************************************************************************
|
|
* 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/>. *
|
|
* *
|
|
**************************************************************************/
|
|
|
|
#ifndef MATERIAL_MATERIALS_H
|
|
#define MATERIAL_MATERIALS_H
|
|
|
|
#include <memory>
|
|
|
|
#include <QDir>
|
|
#include <QSet>
|
|
#include <QString>
|
|
#include <QStringList>
|
|
#include <QTextStream>
|
|
|
|
#include <App/Application.h>
|
|
#include <App/Color.h>
|
|
#include <App/Material.h>
|
|
#include <Base/BaseClass.h>
|
|
|
|
#include <Mod/Material/MaterialGlobal.h>
|
|
|
|
#include "MaterialValue.h"
|
|
#include "Model.h"
|
|
|
|
namespace Materials
|
|
{
|
|
|
|
class MaterialLibrary;
|
|
|
|
class MaterialsExport MaterialProperty: public ModelProperty
|
|
{
|
|
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
|
|
|
public:
|
|
MaterialProperty();
|
|
MaterialProperty(const MaterialProperty& other);
|
|
explicit MaterialProperty(const ModelProperty& other);
|
|
explicit MaterialProperty(const std::shared_ptr<MaterialProperty>& other);
|
|
~MaterialProperty() override = default;
|
|
|
|
MaterialValue::ValueType getType() const
|
|
{
|
|
return _valuePtr->getType();
|
|
}
|
|
|
|
const QString getModelUUID() const;
|
|
QVariant getValue();
|
|
QVariant getValue() const;
|
|
QList<QVariant> getList()
|
|
{
|
|
return _valuePtr->getList();
|
|
}
|
|
QList<QVariant> getList() const
|
|
{
|
|
return _valuePtr->getList();
|
|
}
|
|
bool isNull() const
|
|
{
|
|
return _valuePtr->isNull();
|
|
}
|
|
std::shared_ptr<MaterialValue> getMaterialValue();
|
|
std::shared_ptr<MaterialValue> getMaterialValue() const;
|
|
QString getString() const;
|
|
QString getYAMLString() const;
|
|
QString getDictionaryString() const; // Non-localized string
|
|
bool getBoolean() const
|
|
{
|
|
return getValue().toBool();
|
|
}
|
|
int getInt() const
|
|
{
|
|
return getValue().toInt();
|
|
}
|
|
double getFloat() const
|
|
{
|
|
return getValue().toFloat();
|
|
}
|
|
const Base::Quantity& getQuantity() const;
|
|
QString getURL() const
|
|
{
|
|
return getValue().toString();
|
|
}
|
|
App::Color getColor() const;
|
|
|
|
MaterialProperty& getColumn(int column);
|
|
const MaterialProperty& getColumn(int column) const;
|
|
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 setValue(const std::shared_ptr<MaterialValue>& 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 setList(const QList<QVariant>& value);
|
|
void setURL(const QString& value);
|
|
void setColor(const App::Color& value);
|
|
|
|
MaterialProperty& operator=(const MaterialProperty& other);
|
|
friend QTextStream& operator<<(QTextStream& output, const MaterialProperty& property);
|
|
|
|
bool operator==(const MaterialProperty& other) const;
|
|
bool operator!=(const MaterialProperty& other) const
|
|
{
|
|
return !operator==(other);
|
|
}
|
|
|
|
// void save(QTextStream& stream);
|
|
|
|
// Define precision for displaying floating point values
|
|
static int const PRECISION;
|
|
|
|
protected:
|
|
void setType(const QString& type);
|
|
// void setType(MaterialValue::ValueType type) { _valueType = type; }
|
|
void copyValuePtr(const std::shared_ptr<MaterialValue>& value);
|
|
|
|
void addColumn(MaterialProperty& column)
|
|
{
|
|
_columns.push_back(column);
|
|
}
|
|
|
|
private:
|
|
QString _modelUUID;
|
|
std::shared_ptr<MaterialValue> _valuePtr;
|
|
std::vector<MaterialProperty> _columns;
|
|
};
|
|
|
|
class MaterialsExport Material: public Base::BaseClass
|
|
{
|
|
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
|
|
|
public:
|
|
enum ModelEdit
|
|
{
|
|
ModelEdit_None, // No change
|
|
ModelEdit_Alter, // Existing values are changed
|
|
ModelEdit_Extend // New values added
|
|
};
|
|
|
|
Material();
|
|
Material(const std::shared_ptr<MaterialLibrary>& library,
|
|
const QString& directory,
|
|
const QString& uuid,
|
|
const QString& name);
|
|
Material(const Material& other);
|
|
~Material() override = default;
|
|
|
|
std::shared_ptr<MaterialLibrary> getLibrary() const
|
|
{
|
|
return _library;
|
|
}
|
|
QString getDirectory() const
|
|
{
|
|
return _directory;
|
|
}
|
|
QString getUUID() const
|
|
{
|
|
return _uuid;
|
|
}
|
|
QString getName() const
|
|
{
|
|
return _name;
|
|
}
|
|
QString getAuthorAndLicense() const;
|
|
QString getAuthor() const
|
|
{
|
|
return _author;
|
|
}
|
|
QString getLicense() const
|
|
{
|
|
return _license;
|
|
}
|
|
QString getParentUUID() const
|
|
{
|
|
return _parentUuid;
|
|
}
|
|
QString getDescription() const
|
|
{
|
|
return _description;
|
|
}
|
|
QString getURL() const
|
|
{
|
|
return _url;
|
|
}
|
|
QString getReference() const
|
|
{
|
|
return _reference;
|
|
}
|
|
ModelEdit getEditState() const
|
|
{
|
|
return _editState;
|
|
}
|
|
const QSet<QString>& getTags() const
|
|
{
|
|
return _tags;
|
|
}
|
|
const QSet<QString>* getPhysicalModels() const
|
|
{
|
|
return &_physicalUuids;
|
|
}
|
|
const QSet<QString>* getAppearanceModels() const
|
|
{
|
|
return &_appearanceUuids;
|
|
}
|
|
|
|
App::Material getMaterialAppearance() const;
|
|
|
|
void setLibrary(const std::shared_ptr<MaterialLibrary>& library)
|
|
{
|
|
_library = library;
|
|
}
|
|
void setDirectory(const QString& directory)
|
|
{
|
|
_directory = directory;
|
|
}
|
|
void setUUID(const QString& uuid)
|
|
{
|
|
_uuid = uuid;
|
|
}
|
|
void setName(const QString& name);
|
|
void setAuthor(const QString& author);
|
|
void setLicense(const QString& license);
|
|
void setParentUUID(const QString& uuid);
|
|
void setDescription(const QString& description);
|
|
void setURL(const QString& url);
|
|
void setReference(const QString& reference);
|
|
|
|
void setEditState(ModelEdit newState);
|
|
void setEditStateAlter()
|
|
{
|
|
setEditState(ModelEdit_Alter);
|
|
}
|
|
void setEditStateExtend()
|
|
{
|
|
setEditState(ModelEdit_Extend);
|
|
}
|
|
void setPropertyEditState(const QString& name);
|
|
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 removePhysical(const QString& uuid);
|
|
void addAppearance(const QString& uuid);
|
|
void removeAppearance(const QString& uuid);
|
|
void clearModels();
|
|
void clearInherited();
|
|
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 setPhysicalValue(const QString& name, const std::shared_ptr<MaterialValue>& value);
|
|
void setPhysicalValue(const QString& name, const std::shared_ptr<QList<QVariant>>& value);
|
|
|
|
void setAppearanceValue(const QString& name, const QString& value);
|
|
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);
|
|
std::shared_ptr<MaterialProperty> getAppearanceProperty(const QString& name) const;
|
|
std::shared_ptr<MaterialProperty> getProperty(const QString& name);
|
|
std::shared_ptr<MaterialProperty> getProperty(const QString& name) const;
|
|
QVariant getPhysicalValue(const QString& name) const;
|
|
Base::Quantity getPhysicalQuantity(const QString& name) const;
|
|
QString getPhysicalValueString(const QString& name) const;
|
|
QVariant getAppearanceValue(const QString& name) const;
|
|
Base::Quantity getAppearanceQuantity(const QString& name) const;
|
|
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;
|
|
bool hasPhysicalModel(const QString& uuid) const;
|
|
bool hasAppearanceModel(const QString& uuid) const;
|
|
bool isInherited(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;
|
|
|
|
std::map<QString, std::shared_ptr<MaterialProperty>>& getPhysicalProperties()
|
|
{
|
|
return _physical;
|
|
}
|
|
std::map<QString, std::shared_ptr<MaterialProperty>>& getAppearanceProperties()
|
|
{
|
|
return _appearance;
|
|
}
|
|
std::map<QString, QString>& getLegacyProperties()
|
|
{
|
|
return _legacy;
|
|
}
|
|
|
|
QString getModelByName(const QString& name) const;
|
|
|
|
bool getDereferenced() const
|
|
{
|
|
return _dereferenced;
|
|
}
|
|
void markDereferenced()
|
|
{
|
|
_dereferenced = true;
|
|
}
|
|
void clearDereferenced()
|
|
{
|
|
_dereferenced = false;
|
|
}
|
|
bool isOldFormat() const
|
|
{
|
|
return _oldFormat;
|
|
}
|
|
void setOldFormat(bool isOld)
|
|
{
|
|
_oldFormat = isOld;
|
|
}
|
|
|
|
/*
|
|
* Normalize models by removing any inherited models
|
|
*/
|
|
static QStringList normalizeModels(const QStringList& models);
|
|
|
|
/*
|
|
* Set or change the base material for the current material, updating the properties as
|
|
* required.
|
|
*/
|
|
void updateInheritance(const QString& parent);
|
|
/*
|
|
* Return a list of models that are defined in the parent material but not in this one
|
|
*/
|
|
QStringList inheritedMissingModels(const Material& parent) const;
|
|
/*
|
|
* Return a list of models that are defined in this model but not the parent
|
|
*/
|
|
QStringList inheritedAddedModels(const Material& parent) const;
|
|
/*
|
|
* Return a list of properties that have different values from the parent material
|
|
*/
|
|
void inheritedPropertyDiff(const QString& parent);
|
|
|
|
void save(QTextStream& stream, bool overwrite, bool saveAsCopy, bool saveInherited);
|
|
|
|
/*
|
|
* Assignment operator
|
|
*/
|
|
Material& operator=(const Material& other);
|
|
|
|
/*
|
|
* Set the appearance properties
|
|
*/
|
|
Material& operator=(const App::Material& other);
|
|
|
|
bool operator==(const Material& other) const
|
|
{
|
|
if (&other == this) {
|
|
return true;
|
|
}
|
|
return getTypeId() == other.getTypeId() && _uuid == other._uuid;
|
|
}
|
|
|
|
protected:
|
|
void addModel(const QString& uuid);
|
|
static void removeUUID(QSet<QString>& uuidList, const QString& uuid);
|
|
|
|
static QVariant
|
|
getValue(const std::map<QString, std::shared_ptr<MaterialProperty>>& propertyList,
|
|
const QString& name);
|
|
static QString
|
|
getValueString(const std::map<QString, std::shared_ptr<MaterialProperty>>& propertyList,
|
|
const QString& name);
|
|
|
|
bool modelChanged(const std::shared_ptr<Material>& parent,
|
|
const std::shared_ptr<Model>& model) const;
|
|
bool modelAppearanceChanged(const std::shared_ptr<Material>& parent,
|
|
const std::shared_ptr<Model>& model) const;
|
|
void saveGeneral(QTextStream& stream) const;
|
|
void saveInherits(QTextStream& stream) const;
|
|
void saveModels(QTextStream& stream, bool saveInherited) const;
|
|
void saveAppearanceModels(QTextStream& stream, bool saveInherited) const;
|
|
|
|
private:
|
|
std::shared_ptr<MaterialLibrary> _library;
|
|
QString _directory;
|
|
QString _uuid;
|
|
QString _name;
|
|
QString _author;
|
|
QString _license;
|
|
QString _parentUuid;
|
|
QString _description;
|
|
QString _url;
|
|
QString _reference;
|
|
QSet<QString> _tags;
|
|
QSet<QString> _physicalUuids;
|
|
QSet<QString> _appearanceUuids;
|
|
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;
|
|
};
|
|
|
|
inline QTextStream& operator<<(QTextStream& output, const MaterialProperty& property)
|
|
{
|
|
output << MaterialValue::escapeString(property.getName()) << ":" << property.getYAMLString();
|
|
return output;
|
|
}
|
|
|
|
using MaterialTreeNode = FolderTreeNode<Material>;
|
|
|
|
} // namespace Materials
|
|
|
|
Q_DECLARE_METATYPE(Materials::Material*)
|
|
Q_DECLARE_METATYPE(std::shared_ptr<Materials::Material>)
|
|
|
|
#endif // MATERIAL_MATERIALS_H
|