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