diff --git a/src/Mod/Material/App/MaterialFilter.cpp b/src/Mod/Material/App/MaterialFilter.cpp index 3efe8087f7..e01654a696 100644 --- a/src/Mod/Material/App/MaterialFilter.cpp +++ b/src/Mod/Material/App/MaterialFilter.cpp @@ -62,10 +62,22 @@ TYPESYSTEM_SOURCE(Materials::MaterialFilter, Base::BaseClass) MaterialFilter::MaterialFilter() : _required() , _requiredComplete() + , _requirePhysical(false) + , _requireAppearance(false) {} bool MaterialFilter::modelIncluded(const std::shared_ptr& material) const { + if (_requirePhysical) { + if (!material->hasPhysicalProperties()) { + return false; + } + } + if (_requireAppearance) { + if (!material->hasAppearanceProperties()) { + return false; + } + } for (const auto& complete : _requiredComplete) { if (!material->isModelComplete(complete)) { return false; diff --git a/src/Mod/Material/App/MaterialFilter.h b/src/Mod/Material/App/MaterialFilter.h index 0d2b5d7b21..7645d75971 100644 --- a/src/Mod/Material/App/MaterialFilter.h +++ b/src/Mod/Material/App/MaterialFilter.h @@ -172,6 +172,14 @@ public: void addRequired(const QString& uuid); void addRequiredComplete(const QString& uuid); + /* Require that the materials have physical properties defined. + */ + void requirePhysical(bool required) { _requirePhysical = required; } + + /* Require that the materials have appearance properties defined. + */ + void requireAppearance(bool required) { _requireAppearance = required; } + /* These functions shouldn't normally be called directly. They are * for use by conversion methods, such as MaterialFilterPy */ @@ -190,6 +198,8 @@ private: QString _name; QSet _required; QSet _requiredComplete; + bool _requirePhysical; + bool _requireAppearance; }; } // namespace Materials diff --git a/src/Mod/Material/App/Materials.cpp b/src/Mod/Material/App/Materials.cpp index 0b6f1c3e17..3a5bc13fdd 100644 --- a/src/Mod/Material/App/Materials.cpp +++ b/src/Mod/Material/App/Materials.cpp @@ -1108,6 +1108,16 @@ bool Material::hasLegacyProperties() const return !_legacy.empty(); } +bool Material::hasPhysicalProperties() const +{ + return !_physicalUuids.isEmpty(); +} + +bool Material::hasAppearanceProperties() const +{ + return !_appearanceUuids.isEmpty(); +} + bool Material::isInherited(const QString& uuid) const { if (_physicalUuids.contains(uuid)) { diff --git a/src/Mod/Material/App/Materials.h b/src/Mod/Material/App/Materials.h index 46ae8d9943..52597f1ba0 100644 --- a/src/Mod/Material/App/Materials.h +++ b/src/Mod/Material/App/Materials.h @@ -335,6 +335,8 @@ public: 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; diff --git a/src/Mod/Material/Gui/DlgMaterialImp.cpp b/src/Mod/Material/Gui/DlgMaterialImp.cpp index c970752e64..e89c718c73 100644 --- a/src/Mod/Material/Gui/DlgMaterialImp.cpp +++ b/src/Mod/Material/Gui/DlgMaterialImp.cpp @@ -83,13 +83,11 @@ DlgMaterialImp::DlgMaterialImp(bool floating, QWidget* parent, Qt::WindowFlags f d->floating = floating; - // // Create a filter to only include current format materials - // // that contain the basic render model. - // auto filter = std::make_shared(); - // filter->setIncludeEmptyFolders(false); - // filter->setIncludeLegacy(false); - // filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic); - // d->ui.widgetMaterial->setFilter(filter); + // Create a filter to only include current format materials + // that contain physical properties. + auto filter = std::make_shared(); + filter->requirePhysical(true); + d->ui.widgetMaterial->setFilter(filter); std::vector objects = getSelectionObjects(); setMaterial(objects); diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index ad967dd3a8..408b7a79f9 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -89,8 +89,34 @@ Feature::Feature() { ADD_PROPERTY(Shape, (TopoDS_Shape())); auto mat = Materials::MaterialManager::defaultMaterial(); - // ADD_PROPERTY_TYPE(ShapeMaterial, (mat), osgroup, App::Prop_None, "Shape material"); ADD_PROPERTY(ShapeMaterial, (*mat)); + + // Read only properties based on the material + static const char* group = "PhysicalProperties"; + ADD_PROPERTY_TYPE(MaterialName, + (""), + group, + static_cast(App::Prop_ReadOnly | App::Prop_Output + | App::Prop_NoRecompute | App::Prop_NoPersist), + "Feature material"); + ADD_PROPERTY_TYPE(Density, + (0.0), + group, + static_cast(App::Prop_ReadOnly | App::Prop_Output + | App::Prop_NoRecompute | App::Prop_NoPersist), + "Feature density"); + ADD_PROPERTY_TYPE(Mass, + (0.0), + group, + static_cast(App::Prop_ReadOnly | App::Prop_Output + | App::Prop_NoRecompute | App::Prop_NoPersist), + "Feature mass"); + ADD_PROPERTY_TYPE(Volume, + (1.0), + group, + static_cast(App::Prop_ReadOnly | App::Prop_Output + | App::Prop_NoRecompute | App::Prop_NoPersist), + "Feature volume"); } Feature::~Feature() = default; @@ -1477,11 +1503,40 @@ void Feature::onChanged(const App::Property* prop) } } } + updatePhysicalProperties(); + } else if (prop == &this->ShapeMaterial) { + updatePhysicalProperties(); } GeoFeature::onChanged(prop); } +void Feature::updatePhysicalProperties() +{ + MaterialName.setValue(ShapeMaterial.getValue().getName().toStdString()); + if (ShapeMaterial.getValue().hasPhysicalProperty(QString::fromLatin1("Density"))) { + Density.setValue(ShapeMaterial.getValue() + .getPhysicalQuantity(QString::fromLatin1("Density")) + .getValue()); + } else { + Base::Console().Log("Density is undefined\n"); + Density.setValue(0.0); + } + + auto topoShape = Shape.getValue(); + if (!topoShape.IsNull()) { + GProp_GProps props; + BRepGProp::VolumeProperties(topoShape, props); + Volume.setValue(props.Mass()); + Mass.setValue(Volume.getValue() * Density.getValue()); + } else { + // No shape + Base::Console().Log("No shape defined\n"); + Volume.setValue(0.0); + Mass.setValue(0.0); + } +} + const std::vector& Feature::searchElementCache(const std::string& element, Data::SearchOptions options, diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index c865f0ab4c..4311fe2be2 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -60,6 +61,12 @@ public: PropertyPartShape Shape; Materials::PropertyMaterial ShapeMaterial; + // Convenience properties set when material or shape changes + App::PropertyString MaterialName; + App::PropertyDensity Density; + App::PropertyMass Mass; + App::PropertyVolume Volume; + /** @name methods override feature */ //@{ short mustExecute() const override; @@ -172,6 +179,9 @@ protected: void copyMaterial(Feature* feature); void copyMaterial(App::DocumentObject* link); + /// Update the mass and volume properties + void updatePhysicalProperties(); + void registerElementCache(const std::string &prefix, PropertyPartShape *prop); /** Helper function to obtain mapped and indexed element name from a shape