diff --git a/src/App/PropertyLinks.cpp b/src/App/PropertyLinks.cpp index b82f4b452e..83e72b39f7 100644 --- a/src/App/PropertyLinks.cpp +++ b/src/App/PropertyLinks.cpp @@ -224,8 +224,10 @@ PropertyLinkList::~PropertyLinkList() // before accessing internals make sure the object is not about to be destroyed // otherwise the backlink contains dangling pointers if (!parent->testStatus(ObjectStatus::Destroy)) { - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } } } #endif @@ -251,8 +253,10 @@ void PropertyLinkList::setValue(DocumentObject* lValue) // before accessing internals make sure the object is not about to be destroyed // otherwise the backlink contains dangling pointers if (!parent->testStatus(ObjectStatus::Destroy)) { - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } if (lValue) lValue->_addBackLink(parent); } @@ -282,10 +286,14 @@ void PropertyLinkList::setValues(const std::vector& lValue) // before accessing internals make sure the object is not about to be destroyed // otherwise the backlink contains dangling pointers if (!parent->testStatus(ObjectStatus::Destroy)) { - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); - for(auto *obj : lValue) - obj->_addBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } + for(auto *obj : lValue) { + if (obj) + obj->_addBackLink(parent); + } } } #endif @@ -651,8 +659,10 @@ PropertyLinkSubList::~PropertyLinkSubList() // before accessing internals make sure the object is not about to be destroyed // otherwise the backlink contains dangling pointers if (!parent->testStatus(ObjectStatus::Destroy)) { - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } } } #endif @@ -678,8 +688,10 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue,const char* SubName) // before accessing internals make sure the object is not about to be destroyed // otherwise the backlink contains dangling pointers if (!parent->testStatus(ObjectStatus::Destroy)) { - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } if (lValue) lValue->_addBackLink(parent); } @@ -716,13 +728,17 @@ void PropertyLinkSubList::setValues(const std::vector& lValue,c if (!parent->testStatus(ObjectStatus::Destroy)) { //_lValueList can contain items multiple times, but we trust the document //object to ensure that this works - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } //maintain backlinks. lValue can contain items multiple times, but we trust the document //object to ensure that the backlink is only added once - for(auto *obj : lValue) - obj->_addBackLink(parent); + for(auto *obj : lValue) { + if (obj) + obj->_addBackLink(parent); + } } } #endif @@ -752,13 +768,17 @@ void PropertyLinkSubList::setValues(const std::vector& lValue,c if (!parent->testStatus(ObjectStatus::Destroy)) { //_lValueList can contain items multiple times, but we trust the document //object to ensure that this works - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } //maintain backlinks. lValue can contain items multiple times, but we trust the document //object to ensure that the backlink is only added once - for(auto *obj : lValue) - obj->_addBackLink(parent); + for(auto *obj : lValue) { + if (obj) + obj->_addBackLink(parent); + } } } #endif @@ -780,8 +800,10 @@ void PropertyLinkSubList::setValue(DocumentObject* lValue, const std::vectortestStatus(ObjectStatus::Destroy)) { //_lValueList can contain items multiple times, but we trust the document //object to ensure that this works - for(auto *obj : _lValueList) - obj->_removeBackLink(parent); + for(auto *obj : _lValueList) { + if (obj) + obj->_removeBackLink(parent); + } //maintain backlinks. lValue can contain items multiple times, but we trust the document //object to ensure that the backlink is only added once @@ -1020,10 +1042,18 @@ void PropertyLinkSubList::Save (Base::Writer &writer) const writer.Stream() << writer.ind() << "" << endl; writer.incInd(); for (int i = 0; i < getSize(); i++) { - writer.Stream() << writer.ind() << - "getNameInDocument() << "\" " << - "sub=\"" << _lSubList[i] << "\"/>" << endl; + if (_lValueList[i]) { + writer.Stream() << writer.ind() << + "getNameInDocument() << "\" " << + "sub=\"" << _lSubList[i] << "\"/>" << endl; + } + else { + writer.Stream() << writer.ind() << + "" << endl; + } } writer.decInd(); diff --git a/src/Mod/PartDesign/App/ShapeBinder.cpp b/src/Mod/PartDesign/App/ShapeBinder.cpp index b428083c1b..dbb3c89c94 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.cpp +++ b/src/Mod/PartDesign/App/ShapeBinder.cpp @@ -25,13 +25,17 @@ #ifndef _PreComp_ # include # include +# include +# include # include +# include # include #endif #include "ShapeBinder.h" #include #include +#include #include #ifndef M_PI @@ -69,13 +73,14 @@ short int ShapeBinder::mustExecute(void) const { App::DocumentObjectExecReturn* ShapeBinder::execute(void) { if (!this->isRestoring()) { - Part::Feature* obj = nullptr; + App::GeoFeature* obj = nullptr; std::vector subs; ShapeBinder::getFilteredReferences(&Support, obj, subs); + //if we have a link we rebuild the shape, but we change nothing if we are a simple copy if (obj) { - Part::TopoShape shape = ShapeBinder::buildShapeFromReferences(obj, subs); + Part::TopoShape shape(ShapeBinder::buildShapeFromReferences(obj, subs)); //now, shape is in object's CS, and includes local Placement of obj but nothing else. if (TraceSupport.getValue()) { @@ -96,7 +101,7 @@ App::DocumentObjectExecReturn* ShapeBinder::execute(void) { return Part::Feature::execute(); } -void ShapeBinder::getFilteredReferences(App::PropertyLinkSubList* prop, Part::Feature*& obj, +void ShapeBinder::getFilteredReferences(App::PropertyLinkSubList* prop, App::GeoFeature*& obj, std::vector< std::string >& subobjects) { obj = nullptr; @@ -111,63 +116,96 @@ void ShapeBinder::getFilteredReferences(App::PropertyLinkSubList* prop, Part::Fe //we only allow one part feature, so get the first one we find size_t index = 0; - while (index < objs.size() && !objs[index]->isDerivedFrom(Part::Feature::getClassTypeId())) + for (auto* it : objs) { + if (it && it->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + obj = static_cast(it); + break; + } index++; - - //do we have any part feature? - if (index >= objs.size()) - return; - - obj = static_cast(objs[index]); - - //if we have no subshpape we use the whole shape - if (subs[index].empty()) { - return; } - //collect all subshapes for the object - index = 0; - for (std::string sub : subs) { + //do we have any part feature? + if (obj) { + //if we have no subshpape we use the whole shape + if (subs[index].empty()) { + return; + } - //we only allow subshapes from a single Part::Feature - if (objs[index] != obj) - continue; + //collect all subshapes for the object + for (index = 0; index < objs.size(); index++) { + //we only allow subshapes from a single Part::Feature + if (objs[index] != obj) + continue; - //in this mode the full shape is not allowed, as we already started the subshape - //processing - if (sub.empty()) - continue; + //in this mode the full shape is not allowed, as we already started the subshape + //processing + if (subs[index].empty()) + continue; - subobjects.push_back(sub); + subobjects.push_back(subs[index]); + } + } + else { + // search for Origin features + for (auto* it : objs) { + if (it && it->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { + obj = static_cast(it); + break; + } + else if (it && it->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + obj = static_cast(it); + break; + } + } } } -Part::TopoShape ShapeBinder::buildShapeFromReferences( Part::Feature* obj, std::vector< std::string > subs) { +Part::TopoShape ShapeBinder::buildShapeFromReferences(App::GeoFeature* obj, std::vector< std::string > subs) { if (!obj) return TopoDS_Shape(); - if (subs.empty()) - return obj->Shape.getShape(); + if (obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + Part::Feature* part = static_cast(obj); + if (subs.empty()) + return part->Shape.getValue(); - std::vector shapes; - for (std::string sub : subs) { - shapes.push_back(obj->Shape.getShape().getSubShape(sub.c_str())); - } - - if (shapes.size() == 1){ - //single subshape. Return directly. - return shapes[0]; - } else { - //multiple subshapes. Make a compound. - BRep_Builder builder; - TopoDS_Compound cmp; - builder.MakeCompound(cmp); - for(const TopoDS_Shape& sh : shapes){ - builder.Add(cmp, sh); + std::vector shapes; + for (std::string sub : subs) { + shapes.push_back(part->Shape.getShape().getSubShape(sub.c_str())); + } + + if (shapes.size() == 1) { + //single subshape. Return directly. + return shapes[0]; + } + else { + //multiple subshapes. Make a compound. + BRep_Builder builder; + TopoDS_Compound cmp; + builder.MakeCompound(cmp); + for(const TopoDS_Shape& sh : shapes){ + builder.Add(cmp, sh); + } + return cmp; } - return cmp; } + else if (obj->getTypeId().isDerivedFrom(App::Line::getClassTypeId())) { + gp_Lin line; + BRepBuilderAPI_MakeEdge mkEdge(line); + Part::TopoShape shape(mkEdge.Shape()); + shape.setPlacement(obj->Placement.getValue()); + return shape; + } + else if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId())) { + gp_Pln plane; + BRepBuilderAPI_MakeFace mkFace(plane); + Part::TopoShape shape(mkFace.Shape()); + shape.setPlacement(obj->Placement.getValue()); + return shape; + } + + return TopoDS_Shape(); } void ShapeBinder::handleChangedPropertyType(Base::XMLReader &reader, const char *TypeName, App::Property *prop) @@ -199,7 +237,7 @@ void ShapeBinder::slotChangedObject(const App::DocumentObject& Obj, const App::P if (!Prop.getTypeId().isDerivedFrom(App::PropertyPlacement::getClassTypeId())) return; - Part::Feature* obj = nullptr; + App::GeoFeature* obj = nullptr; std::vector subs; ShapeBinder::getFilteredReferences(&Support, obj, subs); if (obj) { diff --git a/src/Mod/PartDesign/App/ShapeBinder.h b/src/Mod/PartDesign/App/ShapeBinder.h index b5908e75f3..2ef74fa63e 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.h +++ b/src/Mod/PartDesign/App/ShapeBinder.h @@ -51,8 +51,8 @@ public: App::PropertyLinkSubListGlobal Support; App::PropertyBool TraceSupport; - static void getFilteredReferences(App::PropertyLinkSubList* prop, Part::Feature*& object, std::vector< std::string >& subobjects); - static Part::TopoShape buildShapeFromReferences(Feature* obj, std::vector< std::string > subs); + static void getFilteredReferences(App::PropertyLinkSubList* prop, App::GeoFeature*& object, std::vector< std::string >& subobjects); + static Part::TopoShape buildShapeFromReferences(App::GeoFeature* obj, std::vector< std::string > subs); const char* getViewProviderName(void) const { return "PartDesignGui::ViewProviderShapeBinder"; diff --git a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp index 7d7d5e46dc..beb3e84489 100644 --- a/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskDatumParameters.cpp @@ -151,23 +151,28 @@ bool TaskDlgDatumParameters::accept() { if (result == QDialog::DialogCode::Rejected) return false; else if (!dlg.radioXRef->isChecked()) { - std::vector objs; + std::vector copyObjects; + std::vector copySubValues; std::vector subs = pcDatum->Support.getSubValues(); int index = 0; for (App::DocumentObject* obj : pcDatum->Support.getValues()) { if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { - objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, subs[index], dlg.radioIndependent->isChecked())); - copies.push_back(objs.back()); - subs[index] = ""; + auto* copy = PartDesignGui::TaskFeaturePick::makeCopy(obj, subs[index], dlg.radioIndependent->isChecked()); + if (copy) { + copyObjects.push_back(copy); + copies.push_back(copyObjects.back()); + copySubValues.push_back(std::string()); + } } else { - objs.push_back(obj); + copyObjects.push_back(obj); + copySubValues.push_back(subs[index]); } index++; } - pcDatum->Support.setValues(objs, subs); + pcDatum->Support.setValues(copyObjects, copySubValues); } } diff --git a/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp b/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp index 008f9075c9..f195b3e4ed 100644 --- a/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp +++ b/src/Mod/PartDesign/Gui/TaskFeaturePick.cpp @@ -406,9 +406,25 @@ App::DocumentObject* TaskFeaturePick::makeCopy(App::DocumentObject* obj, std::st else shapeProp = &static_cast(copy)->Shape; } + else if(obj->isDerivedFrom(App::Plane::getClassTypeId()) || + obj->isDerivedFrom(App::Line::getClassTypeId())) { - if(independent && shapeProp) { - if(entity.empty()) + copy = App::GetApplication().getActiveDocument()->addObject("PartDesign::ShapeBinder", name.c_str()); + + if (!independent) { + static_cast(copy)->Support.setValue(obj, entity.c_str()); + } + else { + App::GeoFeature* geo = static_cast(obj); + std::vector subvalues; + subvalues.push_back(entity); + Part::TopoShape shape = PartDesign::ShapeBinder::buildShapeFromReferences(geo, subvalues); + static_cast(copy)->Shape.setValue(shape); + } + } + + if (independent && shapeProp) { + if (entity.empty()) shapeProp->setValue(static_cast(obj)->Shape.getValue()); else shapeProp->setValue(static_cast(obj)->Shape.getShape().getSubShape(entity.c_str())); diff --git a/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp b/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp index 3a75e00533..a8eee96342 100644 --- a/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/TaskShapeBinder.cpp @@ -79,7 +79,7 @@ TaskShapeBinder::TaskShapeBinder(ViewProviderShapeBinder *view, bool /*newObj*/, vp = view; //add initial values - Part::Feature* obj = nullptr; + App::GeoFeature* obj = nullptr; std::vector subs; PartDesign::ShapeBinder::getFilteredReferences(&static_cast(vp->getObject())->Support, obj, subs); @@ -227,9 +227,9 @@ bool TaskShapeBinder::referenceSelected(const SelectionChanges& msg) const { std::string subName(msg.pSubName); Part::Feature* selectedObj = nullptr; - Part::Feature* obj = nullptr; + App::GeoFeature* obj = nullptr; std::vector refs; - + PartDesign::ShapeBinder::getFilteredReferences(&static_cast(vp->getObject())->Support, obj, refs); // get selected object diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index c29be1c023..e69bc34fdd 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -124,14 +124,18 @@ void ViewProviderShapeBinder::unsetEdit(int ModNum) { void ViewProviderShapeBinder::highlightReferences(const bool on, bool /*auxiliary*/) { - Part::Feature* obj; + App::GeoFeature* obj = nullptr; std::vector subs; - if(getObject()->isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId())) + if (getObject()->isDerivedFrom(PartDesign::ShapeBinder::getClassTypeId())) PartDesign::ShapeBinder::getFilteredReferences(&static_cast(getObject())->Support, obj, subs); else return; + // stop if not a Part feature was found + if (!obj || !obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return; + PartGui::ViewProviderPart* svp = dynamic_cast( Gui::Application::Instance->getViewProvider(obj)); if (svp == NULL) return; @@ -139,12 +143,12 @@ void ViewProviderShapeBinder::highlightReferences(const bool on, bool /*auxiliar if (on) { if (!subs.empty() && originalLineColors.empty()) { TopTools_IndexedMapOfShape eMap; - TopExp::MapShapes(obj->Shape.getValue(), TopAbs_EDGE, eMap); + TopExp::MapShapes(static_cast(obj)->Shape.getValue(), TopAbs_EDGE, eMap); originalLineColors = svp->LineColorArray.getValues(); std::vector lcolors = originalLineColors; lcolors.resize(eMap.Extent(), svp->LineColor.getValue()); - TopExp::MapShapes(obj->Shape.getValue(), TopAbs_FACE, eMap); + TopExp::MapShapes(static_cast(obj)->Shape.getValue(), TopAbs_FACE, eMap); originalFaceColors = svp->DiffuseColor.getValues(); std::vector fcolors = originalFaceColors; fcolors.resize(eMap.Extent(), svp->ShapeColor.getValue());