// SPDX-License-Identifier: LGPL-2.1-or-later /*************************************************************************** * Copyright (c) 2023 David Carter * * * * This file is part of FreeCAD. * * * * FreeCAD is free software: you can redistribute it and/or modify it * * under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 2.1 of the * * License, or (at your option) any later version. * * * * FreeCAD is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with FreeCAD. If not, see * * . * * * **************************************************************************/ #ifndef MATERIAL_MATERIALS_H #define MATERIAL_MATERIALS_H #include #include #include #include #include #include #include #include #include #include #include #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, QString modelUUID); explicit MaterialProperty(const std::shared_ptr& other); ~MaterialProperty() override = default; MaterialValue::ValueType getType() const { return _valuePtr->getType(); } const QString getModelUUID() const { return _modelUUID; } QVariant getValue(); QVariant getValue() const; QList getList() { return _valuePtr->getList(); } QList getList() const { return _valuePtr->getList(); } bool isNull() const { return _valuePtr->isNull(); } bool isEmpty() const { return _valuePtr->isEmpty(); } std::shared_ptr getMaterialValue(); std::shared_ptr 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(); } Base::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; const std::vector& getColumns() const { return _columns; } 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& value); void setString(const QString& value); void setString(const std::string& 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& value); void setURL(const QString& value); void setColor(const Base::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 validate(const MaterialProperty& other) const; // 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& value); void addColumn(MaterialProperty& column) { _columns.push_back(column); } private: QString _modelUUID; std::shared_ptr _valuePtr; std::vector _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& library, const QString& directory, const QString& uuid, const QString& name); Material(const Material& other); ~Material() override = default; std::shared_ptr getLibrary() const { return _library; } QString getDirectory() const; QString getFilename() const; QString getFilePath() const; 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& getTags() const { return _tags; } const QSet* getPhysicalModels() const { return &_physicalUuids; } const QSet* getAppearanceModels() const { return &_appearanceUuids; } App::Material getMaterialAppearance() const; void setLibrary(const std::shared_ptr& library) { _library = library; } void setDirectory(const QString& directory); void setFilename(const QString& filename); 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); void removeTag(const QString& tag); bool hasTag(const QString& tag) { return _tags.contains(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& value); void setPhysicalValue(const QString& name, const std::shared_ptr>& value); void setPhysicalValue(const QString& name, const QVariant& value); void setAppearanceValue(const QString& name, const QString& value); void setAppearanceValue(const QString& name, const std::shared_ptr& value); void setAppearanceValue(const QString& name, const std::shared_ptr>& value); void setAppearanceValue(const QString& name, const QVariant& value); void setValue(const QString& name, const QString& value); void setValue(const QString& name, const QVariant& value); void setValue(const QString& name, const std::shared_ptr& 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 getPhysicalProperty(const QString& name); std::shared_ptr getPhysicalProperty(const QString& name) const; std::shared_ptr getAppearanceProperty(const QString& name); std::shared_ptr getAppearanceProperty(const QString& name) const; std::shared_ptr getProperty(const QString& name); std::shared_ptr 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; bool hasPhysicalProperties() const; bool hasAppearanceProperties() 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>& getPhysicalProperties() { return _physical; } const std::map>& getPhysicalProperties() const { return _physical; } std::map>& getAppearanceProperties() { return _appearance; } const std::map>& getAppearanceProperties() const { return _appearance; } std::map& 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; } void validate(Material& other) const; protected: void addModel(const QString& uuid); static void removeUUID(QSet& uuidList, const QString& uuid); static QVariant getValue(const std::map>& propertyList, const QString& name); static QString getValueString(const std::map>& propertyList, const QString& name); bool modelChanged(const Material& parent, const Model& model) const; bool modelAppearanceChanged(const Material& parent, const 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 _library; QString _directory; QString _filename; QString _uuid; QString _name; QString _author; QString _license; QString _parentUuid; QString _description; QString _url; QString _reference; QSet _tags; QSet _physicalUuids; QSet _appearanceUuids; QSet _allUuids; // Includes inherited models std::map> _physical; std::map> _appearance; std::map _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; } // namespace Materials Q_DECLARE_METATYPE(Materials::Material*) Q_DECLARE_METATYPE(std::shared_ptr) #endif // MATERIAL_MATERIALS_H