From 03a8ff784176820640050fc74df633acbb449cd5 Mon Sep 17 00:00:00 2001 From: Ajinkya Dahale Date: Sun, 7 Nov 2021 03:39:56 -0500 Subject: [PATCH] [PD] Support adding solid faces for loft and pipe sections With these changes, one face per solid can be added as either the first "profile" or subsequent sections in loft and pipe. This commit depends on `App::PropertyXLinkSubList` preserving the order in which sections are added. A minor change this also adds is that when a solid's face is selected that face is mentioned in the fields instead of the solid (eg `Box:Face1` instead of `Box`). --- src/Mod/PartDesign/App/FeatureLoft.cpp | 52 ++++++++------ src/Mod/PartDesign/App/FeatureLoft.h | 10 +-- src/Mod/PartDesign/App/FeaturePipe.cpp | 72 +++++++++++-------- src/Mod/PartDesign/App/FeaturePipe.h | 14 ++-- src/Mod/PartDesign/Gui/TaskLoftParameters.cpp | 13 ++-- src/Mod/PartDesign/Gui/TaskPipeParameters.cpp | 38 +++++----- .../Gui/TaskSketchBasedParameters.cpp | 14 ++++ .../Gui/TaskSketchBasedParameters.h | 4 ++ 8 files changed, 129 insertions(+), 88 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp index f1d0c62158..3a922a056e 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.cpp +++ b/src/Mod/PartDesign/App/FeatureLoft.cpp @@ -55,7 +55,7 @@ PROPERTY_SOURCE(PartDesign::Loft, PartDesign::ProfileBased) Loft::Loft() { ADD_PROPERTY_TYPE(Sections,(0),"Loft",App::Prop_None,"List of sections"); - Sections.setSize(0); + Sections.setValue(0); ADD_PROPERTY_TYPE(Ruled,(false),"Loft",App::Prop_None,"Create ruled surface"); ADD_PROPERTY_TYPE(Closed,(false),"Loft",App::Prop_None,"Close Last to First Profile"); } @@ -95,44 +95,56 @@ App::DocumentObjectExecReturn *Loft::execute(void) } try { - //setup the location + // setup the location this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); - if(!base.IsNull()) + if (!base.IsNull()) base.Move(invObjLoc); - //build up multisections + // build up multisections auto multisections = Sections.getValues(); - if(multisections.empty()) + if (multisections.empty()) return new App::DocumentObjectExecReturn("Loft: At least one section is needed"); std::vector> wiresections; - for(TopoDS_Wire& wire : wires) + for (TopoDS_Wire& wire : wires) wiresections.emplace_back(1, wire); - for(App::DocumentObject* obj : multisections) { - if(!obj->isDerivedFrom(Part::Feature::getClassTypeId())) + for (auto obj : multisections) { + if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("Loft: All sections need to be part features"); + // if the section is an object's face then take just the face + TopoDS_Shape shape; + if (obj->isDerivedFrom(Part::Part2DObject::getClassTypeId())) + shape = static_cast(obj)->Shape.getValue(); + else { + auto subValues = Sections.getSubValues(obj); + if (subValues.empty()) + throw Base::ValueError("Loft: No valid subelement linked in Part::Feature"); + + shape = static_cast(obj)->Shape.getShape(). getSubShape(subValues[0].c_str()); + } + TopExp_Explorer ex; size_t i=0; - for (ex.Init(static_cast(obj)->Shape.getValue(), TopAbs_WIRE); ex.More(); ex.Next(), ++i) { - if(i>=wiresections.size()) + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next(), ++i) { + if (i>=wiresections.size()) return new App::DocumentObjectExecReturn("Loft: Sections need to have the same amount of inner wires as the base section"); wiresections[i].push_back(TopoDS::Wire(ex.Current())); } - if(i shells; - for(std::vector& wires : wiresections) { + for (std::vector& wires : wiresections) { BRepOffsetAPI_ThruSections mkTS(false, Ruled.getValue(), Precision::Confusion()); - for(TopoDS_Wire& wire : wires) { + for (TopoDS_Wire& wire : wires) { wire.Move(invObjLoc); mkTS.AddWire(wire); } @@ -149,7 +161,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) TopoDS_Shape front = getVerifiedFace(); front.Move(invObjLoc); std::vector backwires; - for(std::vector& wires : wiresections) + for (std::vector& wires : wiresections) backwires.push_back(wires.back()); TopoDS_Shape back = Part::FaceMakerCheese::makeFace(backwires); @@ -158,7 +170,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) sewer.SetTolerance(Precision::Confusion()); sewer.Add(front); sewer.Add(back); - for(TopoDS_Shape& s : shells) + for (TopoDS_Shape& s : shells) sewer.Add(s); sewer.Perform(); @@ -166,7 +178,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) //build the solid BRepBuilderAPI_MakeSolid mkSolid; mkSolid.Add(TopoDS::Shell(sewer.SewedShape())); - if(!mkSolid.IsDone()) + if (!mkSolid.IsDone()) return new App::DocumentObjectExecReturn("Loft: Result is not a solid"); TopoDS_Shape result = mkSolid.Shape(); @@ -178,7 +190,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) AddSubShape.setValue(result); - if(base.IsNull()) { + if (base.IsNull()) { if (getAddSubType() == FeatureAddSub::Subtractive) return new App::DocumentObjectExecReturn("Loft: There is nothing to subtract from\n"); @@ -186,7 +198,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) return App::DocumentObject::StdReturn; } - if(getAddSubType() == FeatureAddSub::Additive) { + if (getAddSubType() == FeatureAddSub::Additive) { BRepAlgoAPI_Fuse mkFuse(base, result); if (!mkFuse.IsDone()) @@ -204,7 +216,7 @@ App::DocumentObjectExecReturn *Loft::execute(void) boolOp = refineShapeIfActive(boolOp); Shape.setValue(getSolid(boolOp)); } - else if(getAddSubType() == FeatureAddSub::Subtractive) { + else if (getAddSubType() == FeatureAddSub::Subtractive) { BRepAlgoAPI_Cut mkCut(base, result); if (!mkCut.IsDone()) diff --git a/src/Mod/PartDesign/App/FeatureLoft.h b/src/Mod/PartDesign/App/FeatureLoft.h index cc4798e356..c3ded6d19e 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.h +++ b/src/Mod/PartDesign/App/FeatureLoft.h @@ -40,9 +40,9 @@ class PartDesignExport Loft : public ProfileBased public: Loft(); - App::PropertyLinkList Sections; - App::PropertyBool Ruled; - App::PropertyBool Closed; + App::PropertyXLinkSubList Sections; + App::PropertyBool Ruled; + App::PropertyBool Closed; /** @name methods override feature */ //@{ @@ -60,14 +60,14 @@ private: }; class PartDesignExport AdditiveLoft : public Loft { - + PROPERTY_HEADER(PartDesign::AdditiveLoft); public: AdditiveLoft(); }; class PartDesignExport SubtractiveLoft : public Loft { - + PROPERTY_HEADER(PartDesign::SubtractiveLoft); public: SubtractiveLoft(); diff --git a/src/Mod/PartDesign/App/FeaturePipe.cpp b/src/Mod/PartDesign/App/FeaturePipe.cpp index dfd410d0ad..f0b863d4f4 100644 --- a/src/Mod/PartDesign/App/FeaturePipe.cpp +++ b/src/Mod/PartDesign/App/FeaturePipe.cpp @@ -82,7 +82,7 @@ PROPERTY_SOURCE(PartDesign::Pipe, PartDesign::ProfileBased) Pipe::Pipe() { ADD_PROPERTY_TYPE(Sections,(0),"Sweep",App::Prop_None,"List of sections"); - Sections.setSize(0); + Sections.setValue(0); ADD_PROPERTY_TYPE(Spine,(0),"Sweep",App::Prop_None,"Path to sweep along"); ADD_PROPERTY_TYPE(SpineTangent,(false),"Sweep",App::Prop_None,"Include tangent edges into path"); ADD_PROPERTY_TYPE(AuxillerySpine,(0),"Sweep",App::Prop_None,"Secondary path to orient sweep"); @@ -129,7 +129,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) //We would need a method to translate the front shape to match the shell starting position somehow... TopoDS_Face face = TopoDS::Face(sketchshape); BRepAdaptor_Surface adapt(face); - if(adapt.GetType() != GeomAbs_Plane) + if (adapt.GetType() != GeomAbs_Plane) return new App::DocumentObjectExecReturn("Pipe: Only planar faces supported"); } @@ -145,7 +145,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) //setup the location this->positionByPrevious(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); - if(!base.IsNull()) + if (!base.IsNull()) base.Move(invObjLoc); //build the paths @@ -162,7 +162,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) // auxiliary TopoDS_Shape auxpath; - if(Mode.getValue()==3) { + if (Mode.getValue()==3) { App::DocumentObject* auxspine = AuxillerySpine.getValue(); if (!(auxspine && auxspine->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) return new App::DocumentObjectExecReturn("No auxiliary spine linked."); @@ -176,38 +176,50 @@ App::DocumentObjectExecReturn *Pipe::execute(void) //build up multisections auto multisections = Sections.getValues(); std::vector> wiresections; - for(TopoDS_Wire& wire : wires) + for (TopoDS_Wire& wire : wires) wiresections.emplace_back(1, wire); //maybe we need a sacling law Handle(Law_Function) scalinglaw; //see if we shall use multiple sections - if(Transformation.getValue() == 1) { + if (Transformation.getValue() == 1) { //TODO: we need to order the sections to prevent occ from crahsing, as makepieshell connects //the sections in the order of adding - for(App::DocumentObject* obj : multisections) { - if(!obj->isDerivedFrom(Part::Feature::getClassTypeId())) + for (App::DocumentObject* obj : multisections) { + if (!obj->isDerivedFrom(Part::Feature::getClassTypeId())) return new App::DocumentObjectExecReturn("All sections need to be part features"); + // if the section is an object's face then take just the face + TopoDS_Shape shape; + if (obj->isDerivedFrom(Part::Part2DObject::getClassTypeId())) + shape = static_cast(obj)->Shape.getValue(); + else { + auto subValues = Sections.getSubValues(obj); + if (subValues.empty()) + throw Base::ValueError("Pipe: No valid subelement in multisection"); + + shape = static_cast(obj)->Shape.getShape(). getSubShape(subValues[0].c_str()); + } + TopExp_Explorer ex; size_t i=0; - for (ex.Init(static_cast(obj)->Shape.getValue(), TopAbs_WIRE); ex.More(); ex.Next()) { - if(i>=wiresections.size()) + for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { + if (i>=wiresections.size()) return new App::DocumentObjectExecReturn("Multisections need to have the same amount of inner wires as the base section"); wiresections[i].push_back(TopoDS::Wire(ex.Current())); ++i; } - if(i shells; std::vector frontwires, backwires; - for(std::vector& wires : wiresections) { + for (std::vector& wires : wiresections) { BRepOffsetAPI_MakePipeShell mkPS(TopoDS::Wire(path)); setupAlgorithm(mkPS, auxpath); - if(!scalinglaw) { - for(TopoDS_Wire& wire : wires) { + if (!scalinglaw) { + for (TopoDS_Wire& wire : wires) { wire.Move(invObjLoc); mkPS.Add(wire); } } else { - for(TopoDS_Wire& wire : wires) { + for (TopoDS_Wire& wire : wires) { wire.Move(invObjLoc); mkPS.SetLaw(wire, scalinglaw); } @@ -277,7 +289,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) sewer.Add(front); sewer.Add(back); - for(TopoDS_Shape& s : shells) + for (TopoDS_Shape& s : shells) sewer.Add(s); sewer.Perform(); @@ -289,7 +301,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) } } - if(!mkSolid.IsDone()) + if (!mkSolid.IsDone()) return new App::DocumentObjectExecReturn("Result is not a solid"); TopoDS_Shape result = mkSolid.Shape(); @@ -302,7 +314,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) //result.Move(invObjLoc); AddSubShape.setValue(result); - if(base.IsNull()) { + if (base.IsNull()) { if (getAddSubType() == FeatureAddSub::Subtractive) return new App::DocumentObjectExecReturn("Pipe: There is nothing to subtract from\n"); @@ -311,7 +323,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) return App::DocumentObject::StdReturn; } - if(getAddSubType() == FeatureAddSub::Additive) { + if (getAddSubType() == FeatureAddSub::Additive) { BRepAlgoAPI_Fuse mkFuse(base, result); if (!mkFuse.IsDone()) @@ -330,7 +342,7 @@ App::DocumentObjectExecReturn *Pipe::execute(void) boolOp = refineShapeIfActive(boolOp); Shape.setValue(getSolid(boolOp)); } - else if(getAddSubType() == FeatureAddSub::Subtractive) { + else if (getAddSubType() == FeatureAddSub::Subtractive) { BRepAlgoAPI_Cut mkCut(base, result); if (!mkCut.IsDone()) @@ -394,7 +406,7 @@ void Pipe::setupAlgorithm(BRepOffsetAPI_MakePipeShell& mkPipeShell, TopoDS_Shape break; } - if(auxiliary) { + if (auxiliary) { mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue()); //mkPipeShell.SetMode(TopoDS::Wire(auxshape), AuxilleryCurvelinear.getValue(), BRepFill_ContactOnBorder); } @@ -410,7 +422,7 @@ void Pipe::getContinuousEdges(Part::TopoShape /*TopShape*/, std::vector< std::st TopExp::MapShapes(TopShape.getShape(), TopAbs_EDGE, mapOfEdges); Base::Console().Message("Initial edges:\n"); - for(int i=0; ishowViewProvider(profile); - QString label = QString::fromUtf8(profile->Label.getValue()); + QString label = make2DLabel(profile, loft->Profile.getSubValues()); ui->profileBaseEdit->setText(label); } for (auto obj : loft->Sections.getValues()) { Gui::Application::Instance->showViewProvider(obj); - QString label = QString::fromUtf8(obj->Label.getValue()); + QString label = make2DLabel(obj, loft->Sections.getSubValues(obj)); QListWidgetItem* item = new QListWidgetItem(); item->setText(label); item->setData(Qt::UserRole, QByteArray(obj->getNameInDocument())); @@ -150,7 +150,7 @@ void TaskLoftParameters::onSelectionChanged(const Gui::SelectionChanges& msg) App::Document* document = App::GetApplication().getDocument(msg.pDocName); App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr; if (object) { - QString label = QString::fromUtf8(object->Label.getValue()); + QString label = make2DLabel(object, {msg.pSubName}); if (selectionMode == refProfile) { ui->profileBaseEdit->setText(label); } @@ -196,7 +196,7 @@ bool TaskLoftParameters::referenceSelected(const Gui::SelectionChanges& msg) con App::DocumentObject* obj = loft->getDocument()->getObject(msg.pObjectName); if (selectionMode == refProfile) { - loft->Profile.setValue(obj); + loft->Profile.setValue(obj, {msg.pSubName}); return true; } else if (selectionMode == refAdd || selectionMode == refRemove) { @@ -206,18 +206,17 @@ bool TaskLoftParameters::referenceSelected(const Gui::SelectionChanges& msg) con if (selectionMode == refAdd) { if (f == refs.end()) - refs.push_back(obj); + loft->Sections.addValue(obj, {msg.pSubName}); else return false; // duplicate selection } else if (selectionMode == refRemove) { if (f != refs.end()) - refs.erase(f); + loft->Sections.removeValue(obj); else return false; } - static_cast(vp->getObject())->Sections.setValues(refs); return true; } } diff --git a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp index 6dd611b873..f8ba9836d3 100644 --- a/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPipeParameters.cpp @@ -118,7 +118,7 @@ TaskPipeParameters::TaskPipeParameters(ViewProviderPipe *PipeView, bool /*newObj //add initial values if (pipe->Profile.getValue()) - ui->profileBaseEdit->setText(QString::fromUtf8(pipe->Profile.getValue()->Label.getValue())); + ui->profileBaseEdit->setText(make2DLabel(pipe->Profile.getValue(), pipe->Profile.getSubValues())); if (pipe->Spine.getValue()) ui->spineBaseEdit->setText(QString::fromUtf8(pipe->Spine.getValue()->Label.getValue())); @@ -186,7 +186,7 @@ void TaskPipeParameters::onSelectionChanged(const Gui::SelectionChanges& msg) App::Document* document = App::GetApplication().getDocument(msg.pDocName); App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr; if (object) { - QString label = QString::fromUtf8(object->Label.getValue()); + QString label = make2DLabel(object, {msg.pSubName}); ui->profileBaseEdit->setText(label); } } @@ -215,7 +215,7 @@ void TaskPipeParameters::onSelectionChanged(const Gui::SelectionChanges& msg) ui->spineBaseEdit->clear(); } } - else if(selectionMode == refObjAdd) { + else if (selectionMode == refObjAdd) { ui->listWidgetReferences->clear(); App::Document* document = App::GetApplication().getDocument(msg.pDocName); @@ -382,12 +382,12 @@ bool TaskPipeParameters::referenceSelected(const SelectionChanges& msg) const { success = false; } else { - pipe->Profile.setValue(profile); + pipe->Profile.setValue(profile, {msg.pSubName}); } // hide the old or new profile again auto* pvp = doc->getViewProvider(pipe->Profile.getValue()); - if(pvp) pvp->setVisible(false); + if (pvp) pvp->setVisible(false); } return success; } @@ -443,12 +443,12 @@ bool TaskPipeParameters::accept() //check the prerequisites for the selected objects //the user has to decide which option we should take if external references are used PartDesign::Pipe* pcPipe = static_cast(getPipeView()->getObject()); - auto pcActiveBody = PartDesignGui::getBodyFor(pcPipe, false); + auto pcActiveBody = PartDesignGui::getBodyFor (pcPipe, false); if (!pcActiveBody) { QMessageBox::warning(this, tr("Input error"), tr("No active body")); return false; } - //auto pcActivePart = PartDesignGui::getPartFor(pcActiveBody, false); + //auto pcActivePart = PartDesignGui::getPartFor (pcActiveBody, false); std::vector copies; bool extReference = false; @@ -473,7 +473,7 @@ bool TaskPipeParameters::accept() extReference = true; } else { - for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { + for (App::DocumentObject* obj : pcPipe->Sections.getValues()) { if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { extReference = true; break; @@ -507,9 +507,9 @@ bool TaskPipeParameters::accept() std::vector objs; int index = 0; - for(App::DocumentObject* obj : pcPipe->Sections.getValues()) { + for (App::DocumentObject* obj : pcPipe->Sections.getValues()) { - if(!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { + if (!pcActiveBody->hasObject(obj) && !pcActiveBody->getOrigin()->hasObject(obj)) { objs.push_back(PartDesignGui::TaskFeaturePick::makeCopy(obj, "", dlg.radioIndependent->isChecked())); copies.push_back(objs.back()); } @@ -604,7 +604,7 @@ TaskPipeOrientation::TaskPipeOrientation(ViewProviderPipe* PipeView, bool /*newO //make sure the user sees an important things: the base feature to select edges and the //spine/auxiliary spine he already selected - if(pipe->AuxillerySpine.getValue()) { + if (pipe->AuxillerySpine.getValue()) { auto* svp = doc->getViewProvider(pipe->AuxillerySpine.getValue()); auxSpineShow = svp->isShow(); svp->show(); @@ -771,7 +771,7 @@ void TaskPipeOrientation::onSelectionChanged(const SelectionChanges& msg) { ui->profileBaseEdit->clear(); } } - else if(selectionMode == refObjAdd) { + else if (selectionMode == refObjAdd) { ui->listWidgetReferences->clear(); App::Document* document = App::GetApplication().getDocument(msg.pDocName); @@ -918,7 +918,7 @@ TaskPipeScaling::TaskPipeScaling(ViewProviderPipe* PipeView, bool /*newObj*/, QW PartDesign::Pipe* pipe = static_cast(PipeView->getObject()); for (auto obj : pipe->Sections.getValues()) { Gui::Application::Instance->showViewProvider(obj); - QString label = QString::fromUtf8(obj->Label.getValue()); + QString label = make2DLabel(obj, pipe->Sections.getSubValues(obj)); QListWidgetItem* item = new QListWidgetItem(); item->setText(label); item->setData(Qt::UserRole, QByteArray(obj->getNameInDocument())); @@ -992,7 +992,7 @@ void TaskPipeScaling::onSelectionChanged(const SelectionChanges& msg) { App::Document* document = App::GetApplication().getDocument(msg.pDocName); App::DocumentObject* object = document ? document->getObject(msg.pObjectName) : nullptr; if (object) { - QString label = QString::fromUtf8(object->Label.getValue()); + QString label = make2DLabel(object, {msg.pSubName}); if (selectionMode == refAdd) { QListWidgetItem* item = new QListWidgetItem(); item->setText(label); @@ -1029,25 +1029,25 @@ bool TaskPipeScaling::referenceSelected(const SelectionChanges& msg) const { //supported, not individual edges of a part //change the references - std::vector refs = static_cast(vp->getObject())->Sections.getValues(); + PartDesign::Pipe* pipe = static_cast(vp->getObject()); + std::vector refs = pipe->Sections.getValues(); App::DocumentObject* obj = vp->getObject()->getDocument()->getObject(msg.pObjectName); std::vector::iterator f = std::find(refs.begin(), refs.end(), obj); if (selectionMode == refAdd) { if (f == refs.end()) - refs.push_back(obj); + pipe->Sections.addValue(obj, {msg.pSubName}); else return false; // duplicate selection } else { if (f != refs.end()) - refs.erase(f); + pipe->Sections.removeValue(obj); else return false; } static_cast(vp)->highlightReferences(ViewProviderPipe::Section, false); - static_cast(vp->getObject())->Sections.setValues(refs); return true; } @@ -1093,7 +1093,7 @@ void TaskPipeScaling::onDeleteSection() void TaskPipeScaling::updateUI(int idx) { //make sure we resize to the size of the current page - for(int i=0; istackedWidget->count(); ++i) + for (int i=0; istackedWidget->count(); ++i) ui->stackedWidget->widget(i)->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); if (idx < ui->stackedWidget->count()) diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp index 473fc4fe2c..d44f7d7f66 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.cpp @@ -220,6 +220,20 @@ QString TaskSketchBasedParameters::getFaceReference(const QString& obj, const QS .arg(QString::fromLatin1(doc->getName()), o, sub); } +QString TaskSketchBasedParameters::make2DLabel(const App::DocumentObject* section, + const std::vector& subValues) +{ + if(section->isDerivedFrom(Part::Part2DObject::getClassTypeId())) + return QString::fromUtf8(section->Label.getValue()); + else { + if(subValues.empty()) + throw Base::ValueError("No valid subelement linked in Part::Feature"); + + return QString::fromUtf8((std::string(section->getNameInDocument()) + + ":" + subValues[0]).c_str()); + } +} + TaskSketchBasedParameters::~TaskSketchBasedParameters() { Gui::Selection().rmvSelectionGate(); diff --git a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h index 539848a435..7ef9c2cd82 100644 --- a/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h +++ b/src/Mod/PartDesign/Gui/TaskSketchBasedParameters.h @@ -61,6 +61,10 @@ protected: QVariant objectNameByLabel(const QString& label, const QVariant& suggest) const; QString getFaceReference(const QString& obj, const QString& sub) const; + /// Create a label for the 2D feature: the objects name if it's already 2D, + /// or the subelement's name if the object is a solid. + QString make2DLabel(const App::DocumentObject* section, + const std::vector& subValues); }; class TaskDlgSketchBasedParameters : public PartDesignGui::TaskDlgFeatureParameters