From 0804d80ebf39e1f95777eaff4686ff6bead382e6 Mon Sep 17 00:00:00 2001 From: David Carter Date: Mon, 21 Oct 2024 10:04:55 -0400 Subject: [PATCH] Materials: Child ignoring parent material Inherit the material from the parent object when creating a new object, such as during a boolean operation, or when extruding a sketch. fixes #15503 --- src/Mod/Part/App/FeatureChamfer.cpp | 2 +- src/Mod/Part/App/FeatureCompound.cpp | 4 +++ src/Mod/Part/App/FeatureFillet.cpp | 2 +- src/Mod/Part/App/FeatureMirroring.cpp | 2 ++ src/Mod/Part/App/FeaturePartBoolean.cpp | 1 + src/Mod/Part/App/FeaturePartCommon.cpp | 4 +++ src/Mod/Part/App/FeaturePartFuse.cpp | 3 +++ src/Mod/Part/App/PartFeature.cpp | 30 +++++++++++++++++++++ src/Mod/Part/App/PartFeature.h | 6 ++++- src/Mod/PartDesign/App/Body.cpp | 14 ++++++++++ src/Mod/PartDesign/App/Feature.cpp | 30 ++++++++++++++++++--- src/Mod/PartDesign/App/Feature.h | 5 ++++ src/Mod/PartDesign/Gui/ViewProviderBody.cpp | 12 --------- src/Mod/PartDesign/Gui/ViewProviderBody.h | 3 --- 14 files changed, 96 insertions(+), 22 deletions(-) diff --git a/src/Mod/Part/App/FeatureChamfer.cpp b/src/Mod/Part/App/FeatureChamfer.cpp index c477a9dc6e..8a29a609d3 100644 --- a/src/Mod/Part/App/FeatureChamfer.cpp +++ b/src/Mod/Part/App/FeatureChamfer.cpp @@ -86,7 +86,7 @@ App::DocumentObjectExecReturn *Chamfer::execute() TopoShape res(0); this->Shape.setValue(res.makeElementShape(mkChamfer,baseTopoShape,Part::OpCodes::Chamfer)); - return Part::Feature::execute(); + return Part::FilletBase::execute(); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); diff --git a/src/Mod/Part/App/FeatureCompound.cpp b/src/Mod/Part/App/FeatureCompound.cpp index d993903141..431ada08c8 100644 --- a/src/Mod/Part/App/FeatureCompound.cpp +++ b/src/Mod/Part/App/FeatureCompound.cpp @@ -69,6 +69,10 @@ App::DocumentObjectExecReturn *Compound::execute() } } this->Shape.setValue(TopoShape().makeElementCompound(shapes)); + if (Links.getSize() > 0) { + App::DocumentObject* link = Links.getValues()[0]; + copyMaterial(link); + } return Part::Feature::execute(); } catch (Standard_Failure& e) { diff --git a/src/Mod/Part/App/FeatureFillet.cpp b/src/Mod/Part/App/FeatureFillet.cpp index d1812394ed..b7fbf423f6 100644 --- a/src/Mod/Part/App/FeatureFillet.cpp +++ b/src/Mod/Part/App/FeatureFillet.cpp @@ -90,7 +90,7 @@ App::DocumentObjectExecReturn *Fillet::execute() TopoShape res(0); this->Shape.setValue(res.makeElementShape(mkFillet,baseTopoShape,Part::OpCodes::Fillet)); - return Part::Feature::execute(); + return Part::FilletBase::execute(); } catch (Standard_Failure& e) { return new App::DocumentObjectExecReturn(e.GetMessageString()); diff --git a/src/Mod/Part/App/FeatureMirroring.cpp b/src/Mod/Part/App/FeatureMirroring.cpp index ee44934f94..9ff4985ce5 100644 --- a/src/Mod/Part/App/FeatureMirroring.cpp +++ b/src/Mod/Part/App/FeatureMirroring.cpp @@ -257,6 +257,8 @@ App::DocumentObjectExecReturn *Mirroring::execute() if (shape.isNull()) Standard_Failure::Raise("Cannot mirror empty shape"); this->Shape.setValue(TopoShape(0).makeElementMirror(shape,ax2)); + copyMaterial(link); + return Part::Feature::execute(); } catch (Standard_Failure& e) { diff --git a/src/Mod/Part/App/FeaturePartBoolean.cpp b/src/Mod/Part/App/FeaturePartBoolean.cpp index 69ce5addd4..8a94de194f 100644 --- a/src/Mod/Part/App/FeaturePartBoolean.cpp +++ b/src/Mod/Part/App/FeaturePartBoolean.cpp @@ -136,6 +136,7 @@ App::DocumentObjectExecReturn* Boolean::execute() res = res.makeElementRefine(); } this->Shape.setValue(res); + copyMaterial(base); return Part::Feature::execute(); } catch (...) { diff --git a/src/Mod/Part/App/FeaturePartCommon.cpp b/src/Mod/Part/App/FeaturePartCommon.cpp index 6c825b2192..9119aeb6e7 100644 --- a/src/Mod/Part/App/FeaturePartCommon.cpp +++ b/src/Mod/Part/App/FeaturePartCommon.cpp @@ -117,6 +117,10 @@ App::DocumentObjectExecReturn *MultiCommon::execute() res = res.makeElementRefine(); } this->Shape.setValue(res); + if (Shapes.getSize() > 0) { + App::DocumentObject* link = Shapes.getValues()[0]; + copyMaterial(link); + } return Part::Feature::execute(); } diff --git a/src/Mod/Part/App/FeaturePartFuse.cpp b/src/Mod/Part/App/FeaturePartFuse.cpp index dbde2834e2..f8bfcbdb23 100644 --- a/src/Mod/Part/App/FeaturePartFuse.cpp +++ b/src/Mod/Part/App/FeaturePartFuse.cpp @@ -208,6 +208,9 @@ App::DocumentObjectExecReturn *MultiFuse::execute() } this->Shape.setValue(res); this->History.setValues(history); + + App::DocumentObject* link = Shapes.getValues()[0]; + copyMaterial(link); return Part::Feature::execute(); } catch (Standard_Failure& e) { diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 9f294b4cc7..17ab7a9a21 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -128,6 +128,26 @@ PyObject *Feature::getPyObject() return Py::new_reference_to(PythonObject); } +void Feature::copyMaterial(Feature* feature) +{ + auto mat = Materials::MaterialManager::defaultMaterial(); + if (feature) { + if (ShapeMaterial.getValue().getUUID() != feature->ShapeMaterial.getValue().getUUID()) { + if (ShapeMaterial.getValue().getUUID() == mat->getUUID()) { + ShapeMaterial.setValue(feature->ShapeMaterial.getValue()); + } + } + } +} + +void Feature::copyMaterial(App::DocumentObject* link) +{ + auto feature = dynamic_cast(link); + if (feature) { + copyMaterial(feature); + } +} + /** * Override getElementName to support the Export type. Other calls are passed to the original * method @@ -1709,6 +1729,16 @@ short FilletBase::mustExecute() const return 0; } +App::DocumentObjectExecReturn* FilletBase::execute() +{ + App::DocumentObject* link = this->Base.getValue(); + if (!link) { + return new App::DocumentObjectExecReturn("No object linked"); + } + copyMaterial(link); + return Part::Feature::execute(); +} + void FilletBase::onChanged(const App::Property *prop) { if(getDocument() && !getDocument()->testStatus(App::Document::Restoring)) { if(prop == &Edges || prop == &Base) { diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index 8f49ec38d8..8060a8e2fc 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -169,6 +169,9 @@ protected: void onBeforeChange(const App::Property* prop) override; void onChanged(const App::Property* prop) override; + void copyMaterial(Feature* feature); + void copyMaterial(App::DocumentObject* link); + void registerElementCache(const std::string &prefix, PropertyPartShape *prop); /** Helper function to obtain mapped and indexed element name from a shape @@ -210,7 +213,8 @@ public: App::PropertyLinkSub EdgeLinks; short mustExecute() const override; - void onUpdateElementReference(const App::Property *prop) override; + App::DocumentObjectExecReturn* execute() override; + void onUpdateElementReference(const App::Property* prop) override; protected: void onDocumentRestored() override; diff --git a/src/Mod/PartDesign/App/Body.cpp b/src/Mod/PartDesign/App/Body.cpp index 9c8cbebcd0..82ce60f2af 100644 --- a/src/Mod/PartDesign/App/Body.cpp +++ b/src/Mod/PartDesign/App/Body.cpp @@ -471,6 +471,20 @@ void Body::onChanged(const App::Property* prop) { } } + else if (prop == &ShapeMaterial) { + std::vector features = Group.getValues(); + if (!features.empty()) { + for (auto it : features) { + auto feature = dynamic_cast(it); + if (feature) { + if (feature->ShapeMaterial.getValue().getUUID() + != ShapeMaterial.getValue().getUUID()) { + feature->ShapeMaterial.setValue(ShapeMaterial.getValue()); + } + } + } + } + } } Part::BodyBase::onChanged(prop); diff --git a/src/Mod/PartDesign/App/Feature.cpp b/src/Mod/PartDesign/App/Feature.cpp index 9bec74bedb..060dad41bc 100644 --- a/src/Mod/PartDesign/App/Feature.cpp +++ b/src/Mod/PartDesign/App/Feature.cpp @@ -32,11 +32,11 @@ # include #endif +#include "App/OriginFeature.h" #include #include -#include #include -#include "App/OriginFeature.h" +#include #include #include "Feature.h" @@ -66,6 +66,8 @@ Feature::Feature() App::DocumentObjectExecReturn* Feature::recompute() { + setMaterialToBodyMaterial(); + SuppressedShape.setValue(TopoShape()); if (!Suppressed.getValue()) { @@ -97,6 +99,18 @@ App::DocumentObjectExecReturn* Feature::recompute() return App::DocumentObject::StdReturn; } +void Feature::setMaterialToBodyMaterial() +{ + auto body = getFeatureBody(); + if (body) { + // Ensure the part has the same material as the body + auto feature = dynamic_cast(body); + if (feature) { + copyMaterial(feature); + } + } +} + void Feature::updateSuppressedShape() { auto baseShape = getBaseTopoShape(true); @@ -166,6 +180,14 @@ void Feature::onChanged(const App::Property *prop) body->insertObject(BaseFeature.getValue(), this); } } + } else if (prop == &ShapeMaterial) { + auto body = Body::findBodyOf(this); + if (body) { + if (body->ShapeMaterial.getValue().getUUID() + != ShapeMaterial.getValue().getUUID()) { + body->ShapeMaterial.setValue(ShapeMaterial.getValue()); + } + } } } Part::Feature::onChanged(prop); @@ -375,7 +397,7 @@ Body* Feature::getFeatureBody() const { return nullptr; } -App::DocumentObject *Feature::getSubObject(const char *subname, +App::DocumentObject *Feature::getSubObject(const char *subname, PyObject **pyObj, Base::Matrix4D *pmat, bool transform, int depth) const { if (subname && subname != Data::findElementName(subname)) { @@ -400,7 +422,7 @@ App::DocumentObject *Feature::getSubObject(const char *subname, // an inverse transform. _mat = Placement.getValue().inverse().toMatrix(); if (pmat) - *pmat *= _mat; + *pmat *= _mat; else pmat = &_mat; } diff --git a/src/Mod/PartDesign/App/Feature.h b/src/Mod/PartDesign/App/Feature.h index 6d3efabbef..05b8744af6 100644 --- a/src/Mod/PartDesign/App/Feature.h +++ b/src/Mod/PartDesign/App/Feature.h @@ -110,6 +110,11 @@ protected: void updateSuppressedShape(); + /** + * Set the Material To Body Material object + */ + void setMaterialToBodyMaterial(); + /// Grab any point from the given face static const gp_Pnt getPointFromFace(const TopoDS_Face& f); /// Make a shape from a base plane (convenience method) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp index 79947520cf..fffc836bdc 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.cpp @@ -247,23 +247,11 @@ void ViewProviderBody::updateData(const App::Property* prop) static_cast(vp)->setTipIcon(feature == tip); } } - - if (tip) - copyColorsfromTip(tip); } PartGui::ViewProviderPart::updateData(prop); } -void ViewProviderBody::copyColorsfromTip(App::DocumentObject* tip) { - // update ShapeAppearance - Gui::ViewProvider* vptip = Gui::Application::Instance->getViewProvider(tip); - if (vptip && vptip->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { - auto materials = static_cast(vptip)->ShapeAppearance.getValues(); - this->ShapeAppearance.setValues(materials); - } -} - void ViewProviderBody::slotChangedObjectApp ( const App::DocumentObject& obj, const App::Property& prop ) { if(App::GetApplication().isRestoring()) diff --git a/src/Mod/PartDesign/Gui/ViewProviderBody.h b/src/Mod/PartDesign/Gui/ViewProviderBody.h index f601d71652..394d6975f6 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderBody.h +++ b/src/Mod/PartDesign/Gui/ViewProviderBody.h @@ -97,9 +97,6 @@ protected: /// Set Feature viewprovider into visual body mode void setVisualBodyMode(bool bodymode); -private: - void copyColorsfromTip(App::DocumentObject* tip); - private: static const char* BodyModeEnum[];