diff --git a/src/Mod/Part/App/BSplineSurfacePyImp.cpp b/src/Mod/Part/App/BSplineSurfacePyImp.cpp
index 45701f8a20bc..da7f502fc6a7 100644
--- a/src/Mod/Part/App/BSplineSurfacePyImp.cpp
+++ b/src/Mod/Part/App/BSplineSurfacePyImp.cpp
@@ -1514,6 +1514,7 @@ PyObject* BSplineSurfacePy::buildFromPolesMultsKnots(PyObject *args, PyObject *k
/*!
* \code
+import math
c = Part.Circle()
c.Radius=50
c = c.trim(0, math.pi)
diff --git a/src/Mod/Surface/App/AppSurface.cpp b/src/Mod/Surface/App/AppSurface.cpp
index d9e094487c96..b980c7009799 100644
--- a/src/Mod/Surface/App/AppSurface.cpp
+++ b/src/Mod/Surface/App/AppSurface.cpp
@@ -33,6 +33,7 @@
#include "FeatureCut.h"
#include "FeatureGeomFillSurface.h"
#include "FeatureExtend.h"
+#include "FeatureSections.h"
#include
#include
@@ -80,6 +81,7 @@ PyMOD_INIT_FUNC(Surface)
Surface::Cut ::init();
Surface::GeomFillSurface ::init();
Surface::Extend ::init();
+ Surface::Sections ::init();
PyMOD_Return(mod);
}
diff --git a/src/Mod/Surface/App/CMakeLists.txt b/src/Mod/Surface/App/CMakeLists.txt
index 78b8a6218e03..c6bf6d8423fb 100644
--- a/src/Mod/Surface/App/CMakeLists.txt
+++ b/src/Mod/Surface/App/CMakeLists.txt
@@ -27,6 +27,8 @@ SET(Surface_SRCS
FeatureGeomFillSurface.h
FeatureFilling.cpp
FeatureFilling.h
+ FeatureSections.cpp
+ FeatureSections.h
FeatureSewing.cpp
FeatureSewing.h
FeatureCut.cpp
diff --git a/src/Mod/Surface/App/FeatureSections.cpp b/src/Mod/Surface/App/FeatureSections.cpp
new file mode 100644
index 000000000000..9583f8b31681
--- /dev/null
+++ b/src/Mod/Surface/App/FeatureSections.cpp
@@ -0,0 +1,103 @@
+/***************************************************************************
+ * Copyright (c) 2020 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#ifndef _PreComp_
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#include "FeatureSections.h"
+#include
+#include
+
+using namespace Surface;
+
+PROPERTY_SOURCE(Surface::Sections, Part::Spline)
+
+Sections::Sections()
+{
+ ADD_PROPERTY_TYPE(NSections,(nullptr), "Sections", App::Prop_None, "Section curves");
+ NSections.setScope(App::LinkScope::Global);
+}
+
+Sections::~Sections()
+{
+}
+
+App::DocumentObjectExecReturn *Sections::execute(void)
+{
+ TColGeom_SequenceOfCurve curveSeq;
+ auto edge_obj = NSections.getValues();
+ auto edge_sub = NSections.getSubValues();
+ if (edge_obj.size() == edge_sub.size()) {
+ for (std::size_t index = 0; index < edge_obj.size(); index++) {
+ // get the part object
+ App::DocumentObject* obj = edge_obj[index];
+ const std::string& sub = edge_sub[index];
+ if (obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) {
+ // get the sub-edge of the part's shape
+ const Part::TopoShape& shape = static_cast(obj)->Shape.getShape();
+ TopoDS_Shape edge = shape.getSubShape(sub.c_str());
+ if (!edge.IsNull() && edge.ShapeType() == TopAbs_EDGE) {
+ BRepAdaptor_Curve curve_adapt(TopoDS::Edge(edge));
+ const TopLoc_Location& loc = edge.Location();
+ Handle(Geom_TrimmedCurve) hCurve = new Geom_TrimmedCurve(curve_adapt.Curve().Curve(),
+ curve_adapt.FirstParameter(),
+ curve_adapt.LastParameter());
+ if (!loc.IsIdentity()) {
+ hCurve->Transform(loc.Transformation());
+ }
+ curveSeq.Append(hCurve);
+ }
+ }
+ }
+ }
+
+ if (curveSeq.Length() < 2)
+ return new App::DocumentObjectExecReturn("At least two sections are required.");
+
+ GeomFill_NSections fillOp(curveSeq);
+ fillOp.ComputeSurface();
+
+ Handle(Geom_BSplineSurface) aSurf = fillOp.BSplineSurface();
+ if (aSurf.IsNull())
+ return new App::DocumentObjectExecReturn("Failed to create surface from sections.");
+
+ BRepBuilderAPI_MakeFace mkFace(aSurf
+#if OCC_VERSION_HEX >= 0x060502
+ , Precision::Confusion()
+#endif
+ );
+
+ Shape.setValue(mkFace.Face());
+ return StdReturn;
+}
diff --git a/src/Mod/Surface/App/FeatureSections.h b/src/Mod/Surface/App/FeatureSections.h
new file mode 100644
index 000000000000..065d693e0c3d
--- /dev/null
+++ b/src/Mod/Surface/App/FeatureSections.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * Copyright (c) 2020 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#ifndef SURFACE_FEATURESECTIONS_H
+#define SURFACE_FEATURESECTIONS_H
+
+#include
+#include
+#include
+#include
+
+namespace Surface
+{
+
+class SurfaceExport Sections : public Part::Spline
+{
+ PROPERTY_HEADER_WITH_OVERRIDE(Surface::Sections);
+
+public:
+ Sections();
+ ~Sections();
+
+ App::PropertyLinkSubList NSections;
+
+ // recalculate the feature
+ App::DocumentObjectExecReturn *execute(void) override;
+ /// returns the type name of the view provider
+ const char* getViewProviderName(void) const override {
+ return "SurfaceGui::ViewProviderSections";
+ }
+};
+
+}//Namespace Surface
+
+#endif
diff --git a/src/Mod/Surface/App/PreCompiled.h b/src/Mod/Surface/App/PreCompiled.h
index f44d96f62764..624b78d3e110 100644
--- a/src/Mod/Surface/App/PreCompiled.h
+++ b/src/Mod/Surface/App/PreCompiled.h
@@ -61,6 +61,7 @@
//opencascade
#include "OpenCascadeAll.h"
+#include
#endif //_PreComp_
diff --git a/src/Mod/Surface/Gui/AppSurfaceGui.cpp b/src/Mod/Surface/Gui/AppSurfaceGui.cpp
index 4410b2a58529..415f001c3ada 100644
--- a/src/Mod/Surface/Gui/AppSurfaceGui.cpp
+++ b/src/Mod/Surface/Gui/AppSurfaceGui.cpp
@@ -36,6 +36,7 @@
#include "Workbench.h"
#include "TaskGeomFillSurface.h"
#include "TaskFilling.h"
+#include "TaskSections.h"
// use a different name to CreateCommand()
void CreateSurfaceCommands(void);
@@ -79,6 +80,7 @@ PyMOD_INIT_FUNC(SurfaceGui)
SurfaceGui::Workbench::init();
SurfaceGui::ViewProviderGeomFillSurface ::init();
SurfaceGui::ViewProviderFilling ::init();
+ SurfaceGui::ViewProviderSections ::init();
// SurfaceGui::ViewProviderCut::init();
diff --git a/src/Mod/Surface/Gui/CMakeLists.txt b/src/Mod/Surface/Gui/CMakeLists.txt
index 87b157949174..c09ff9601a18 100644
--- a/src/Mod/Surface/Gui/CMakeLists.txt
+++ b/src/Mod/Surface/Gui/CMakeLists.txt
@@ -28,6 +28,7 @@ set(SurfaceGui_MOC_HDRS
TaskFillingUnbound.h
TaskFillingVertex.h
TaskGeomFillSurface.h
+ TaskSections.h
)
fc_wrap_cpp(SurfaceGui_MOC_SRCS ${SurfaceGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${SurfaceGui_MOC_SRCS})
@@ -43,6 +44,7 @@ SET(SurfaceGui_UIC_SRCS
TaskFillingUnbound.ui
TaskFillingVertex.ui
TaskGeomFillSurface.ui
+ TaskSections.ui
)
if (BUILD_QT5)
@@ -62,6 +64,8 @@ SET(SurfaceGui_SRCS
TaskFillingVertex.h
TaskGeomFillSurface.cpp
TaskGeomFillSurface.h
+ TaskSections.cpp
+ TaskSections.h
AppSurfaceGui.cpp
Command.cpp
PreCompiled.cpp
diff --git a/src/Mod/Surface/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp
index 0106c5a8bb5a..89f955ad6e97 100644
--- a/src/Mod/Surface/Gui/Command.cpp
+++ b/src/Mod/Surface/Gui/Command.cpp
@@ -261,6 +261,35 @@ bool CmdSurfaceExtendFace::isActive(void)
return Gui::Selection().countObjectsOfType(Part::Feature::getClassTypeId()) == 1;
}
+DEF_STD_CMD_A(CmdSurfaceSections)
+
+CmdSurfaceSections::CmdSurfaceSections()
+ :Command("Surface_Sections")
+{
+ sAppModule = "Surface";
+ sGroup = QT_TR_NOOP("Surface");
+ sMenuText = QT_TR_NOOP("Sections...");
+ sToolTipText = QT_TR_NOOP("Creates a surface from a series of section curves");
+ sStatusTip = QT_TR_NOOP("Creates a surface from a series of section curves");
+ sWhatsThis = "Surface_Sections";
+ //sPixmap = "Surface_Sections";
+}
+
+void CmdSurfaceSections::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ std::string FeatName = getUniqueObjectName("Surface");
+
+ openCommand("Create surface");
+ doCommand(Doc, "App.ActiveDocument.addObject(\"Surface::Sections\",\"%s\")", FeatName.c_str());
+ doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", FeatName.c_str());
+}
+
+bool CmdSurfaceSections::isActive(void)
+{
+ return hasActiveDocument();
+}
+
void CreateSurfaceCommands(void)
{
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
@@ -270,4 +299,5 @@ void CreateSurfaceCommands(void)
rcCmdMgr.addCommand(new CmdSurfaceGeomFillSurface());
rcCmdMgr.addCommand(new CmdSurfaceCurveOnMesh());
rcCmdMgr.addCommand(new CmdSurfaceExtendFace());
+ rcCmdMgr.addCommand(new CmdSurfaceSections());
}
diff --git a/src/Mod/Surface/Gui/TaskSections.cpp b/src/Mod/Surface/Gui/TaskSections.cpp
new file mode 100644
index 000000000000..b24425db54cc
--- /dev/null
+++ b/src/Mod/Surface/Gui/TaskSections.cpp
@@ -0,0 +1,603 @@
+/***************************************************************************
+ * Copyright (c) 2017 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#include "PreCompiled.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "TaskSections.h"
+#include "ui_TaskSections.h"
+
+
+using namespace SurfaceGui;
+
+PROPERTY_SOURCE(SurfaceGui::ViewProviderSections, PartGui::ViewProviderSpline)
+
+namespace SurfaceGui {
+
+void ViewProviderSections::setupContextMenu(QMenu* menu, QObject* receiver, const char* member)
+{
+ QAction* act;
+ act = menu->addAction(QObject::tr("Edit sections"), receiver, member);
+ act->setData(QVariant((int)ViewProvider::Default));
+ PartGui::ViewProviderSpline::setupContextMenu(menu, receiver, member);
+}
+
+bool ViewProviderSections::setEdit(int ModNum)
+{
+ if (ModNum == ViewProvider::Default ) {
+ // When double-clicking on the item for this sketch the
+ // object unsets and sets its edit mode without closing
+ // the task panel
+
+ Surface::Sections* obj = static_cast(this->getObject());
+
+ Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
+
+ // start the edit dialog
+ if (dlg) {
+ TaskSections* tDlg = qobject_cast(dlg);
+ if (tDlg)
+ tDlg->setEditedObject(obj);
+ Gui::Control().showDialog(dlg);
+ }
+ else {
+ Gui::Control().showDialog(new TaskSections(this, obj));
+ }
+ return true;
+ }
+ else {
+ return ViewProviderSpline::setEdit(ModNum);
+ }
+}
+
+void ViewProviderSections::unsetEdit(int ModNum)
+{
+ if (ModNum == ViewProvider::Default) {
+ // when pressing ESC make sure to close the dialog
+ QTimer::singleShot(0, &Gui::Control(), SLOT(closeDialog()));
+ }
+ else {
+ PartGui::ViewProviderSpline::unsetEdit(ModNum);
+ }
+}
+
+QIcon ViewProviderSections::getIcon(void) const
+{
+ return Gui::BitmapFactory().pixmap("BSplineSurf");
+}
+
+void ViewProviderSections::highlightReferences(ShapeType type, const References& refs, bool on)
+{
+ for (auto it : refs) {
+ Part::Feature* base = dynamic_cast(it.first);
+ if (base) {
+ PartGui::ViewProviderPartExt* svp = dynamic_cast(
+ Gui::Application::Instance->getViewProvider(base));
+ if (svp) {
+ switch (type) {
+ case ViewProviderSections::Vertex:
+ if (on) {
+ std::vector colors;
+ TopTools_IndexedMapOfShape vMap;
+ TopExp::MapShapes(base->Shape.getValue(), TopAbs_VERTEX, vMap);
+ colors.resize(vMap.Extent(), svp->PointColor.getValue());
+
+ for (auto jt : it.second) {
+ // check again that the index is in range because it's possible that the
+ // sub-names are invalid
+ std::size_t idx = static_cast(std::stoi(jt.substr(6)) - 1);
+ if (idx < colors.size())
+ colors[idx] = App::Color(1.0,0.0,1.0); // magenta
+ }
+
+ svp->setHighlightedPoints(colors);
+ }
+ else {
+ svp->unsetHighlightedPoints();
+ }
+ break;
+ case ViewProviderSections::Edge:
+ if (on) {
+ std::vector colors;
+ TopTools_IndexedMapOfShape eMap;
+ TopExp::MapShapes(base->Shape.getValue(), TopAbs_EDGE, eMap);
+ colors.resize(eMap.Extent(), svp->LineColor.getValue());
+
+ for (auto jt : it.second) {
+ std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1);
+ // check again that the index is in range because it's possible that the
+ // sub-names are invalid
+ if (idx < colors.size())
+ colors[idx] = App::Color(1.0,0.0,1.0); // magenta
+ }
+
+ svp->setHighlightedEdges(colors);
+ }
+ else {
+ svp->unsetHighlightedEdges();
+ }
+ break;
+ case ViewProviderSections::Face:
+ if (on) {
+ std::vector colors;
+ TopTools_IndexedMapOfShape fMap;
+ TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap);
+ colors.resize(fMap.Extent(), svp->ShapeColor.getValue());
+
+ for (auto jt : it.second) {
+ std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1);
+ // check again that the index is in range because it's possible that the
+ // sub-names are invalid
+ if (idx < colors.size())
+ colors[idx] = App::Color(1.0,0.0,1.0); // magenta
+ }
+
+ svp->setHighlightedFaces(colors);
+ }
+ else {
+ svp->unsetHighlightedFaces();
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+class SectionsPanel::ShapeSelection : public Gui::SelectionFilterGate
+{
+public:
+ ShapeSelection(SectionsPanel::SelectionMode& mode, Surface::Sections* editedObject)
+ : Gui::SelectionFilterGate(static_cast(nullptr))
+ , mode(mode)
+ , editedObject(editedObject)
+ {
+ }
+ ~ShapeSelection()
+ {
+ mode = SectionsPanel::None;
+ }
+ /**
+ * Allow the user to pick only edges.
+ */
+ bool allow(App::Document*, App::DocumentObject* pObj, const char* sSubName)
+ {
+ // don't allow references to itself
+ if (pObj == editedObject)
+ return false;
+ if (!pObj->isDerivedFrom(Part::Feature::getClassTypeId()))
+ return false;
+
+ if (!sSubName || sSubName[0] == '\0')
+ return false;
+
+ switch (mode) {
+ case SectionsPanel::AppendEdge:
+ return allowEdge(true, pObj, sSubName);
+ case SectionsPanel::RemoveEdge:
+ return allowEdge(false, pObj, sSubName);
+ default:
+ return false;
+ }
+ }
+
+private:
+ bool allowEdge(bool appendEdges, App::DocumentObject* pObj, const char* sSubName)
+ {
+ std::string element(sSubName);
+ if (element.substr(0,4) != "Edge")
+ return false;
+
+ auto links = editedObject->NSections.getSubListValues();
+ for (auto it : links) {
+ if (it.first == pObj) {
+ for (auto jt : it.second) {
+ if (jt == sSubName)
+ return !appendEdges;
+ }
+ }
+ }
+
+ return appendEdges;
+ }
+
+private:
+ SectionsPanel::SelectionMode& mode;
+ Surface::Sections* editedObject;
+};
+
+// ----------------------------------------------------------------------------
+
+SectionsPanel::SectionsPanel(ViewProviderSections* vp, Surface::Sections* obj) : ui(new Ui_Sections())
+{
+ ui->setupUi(this);
+ ui->statusLabel->clear();
+
+ selectionMode = None;
+ this->vp = vp;
+ checkCommand = true;
+ setEditedObject(obj);
+
+ // Create context menu
+ QAction* action = new QAction(tr("Remove"), this);
+ action->setShortcut(QKeySequence::Delete);
+ ui->listSections->addAction(action);
+ connect(action, SIGNAL(triggered()), this, SLOT(onDeleteEdge()));
+ ui->listSections->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ connect(ui->listSections->model(),
+ SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this, SLOT(onIndexesMoved()));
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+SectionsPanel::~SectionsPanel()
+{
+}
+
+// stores object pointer, its old fill type and adjusts radio buttons according to it.
+void SectionsPanel::setEditedObject(Surface::Sections* fea)
+{
+ editedObject = fea;
+
+ // get the section edges
+ auto objects = editedObject->NSections.getValues();
+ auto edges = editedObject->NSections.getSubValues();
+ auto count = objects.size();
+
+ App::Document* doc = editedObject->getDocument();
+ for (std::size_t i=0; ilistSections);
+ ui->listSections->addItem(item);
+
+ QString text = QString::fromLatin1("%1.%2")
+ .arg(QString::fromUtf8(obj->Label.getValue()))
+ .arg(QString::fromStdString(edge));
+ item->setText(text);
+
+ // The user data field of a list widget item
+ // is a list of five elementa:
+ // 1. document name
+ // 2. object name
+ // 3. sub-element name of the edge
+ QList data;
+ data << QByteArray(doc->getName());
+ data << QByteArray(obj->getNameInDocument());
+ data << QByteArray(edge.c_str());
+ item->setData(Qt::UserRole, data);
+ }
+
+ // attach this document observer
+ attachDocument(Gui::Application::Instance->getDocument(doc));
+}
+
+void SectionsPanel::changeEvent(QEvent *e)
+{
+ if (e->type() == QEvent::LanguageChange) {
+ ui->retranslateUi(this);
+ }
+ else {
+ QWidget::changeEvent(e);
+ }
+}
+
+void SectionsPanel::open()
+{
+ checkOpenCommand();
+
+ // highlight the boundary edges
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), true);
+
+ Gui::Selection().clearSelection();
+}
+
+void SectionsPanel::clearSelection()
+{
+ Gui::Selection().clearSelection();
+}
+
+void SectionsPanel::checkOpenCommand()
+{
+ if (checkCommand && !Gui::Command::hasPendingCommand()) {
+ std::string Msg("Edit ");
+ Msg += editedObject->Label.getValue();
+ Gui::Command::openCommand(Msg.c_str());
+ checkCommand = false;
+ }
+}
+
+void SectionsPanel::slotUndoDocument(const Gui::Document&)
+{
+ checkCommand = true;
+}
+
+void SectionsPanel::slotRedoDocument(const Gui::Document&)
+{
+ checkCommand = true;
+}
+
+void SectionsPanel::slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj)
+{
+ // If this view provider is being deleted then reset the colors of
+ // referenced part objects. The dialog will be deleted later.
+ if (this->vp == &Obj) {
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), false);
+ }
+}
+
+bool SectionsPanel::accept()
+{
+ selectionMode = None;
+ Gui::Selection().rmvSelectionGate();
+
+ if (editedObject->mustExecute())
+ editedObject->recomputeFeature();
+ if (!editedObject->isValid()) {
+ QMessageBox::warning(this, tr("Invalid object"),
+ QString::fromLatin1(editedObject->getStatusString()));
+ return false;
+ }
+
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), false);
+
+ return true;
+}
+
+bool SectionsPanel::reject()
+{
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), false);
+
+ selectionMode = None;
+ Gui::Selection().rmvSelectionGate();
+
+ return true;
+}
+
+void SectionsPanel::on_buttonEdgeAdd_clicked()
+{
+ // 'selectionMode' is passed by reference and changed when the filter is deleted
+ Gui::Selection().addSelectionGate(new ShapeSelection(selectionMode, editedObject));
+ selectionMode = AppendEdge;
+}
+
+void SectionsPanel::on_buttonEdgeRemove_clicked()
+{
+ // 'selectionMode' is passed by reference and changed when the filter is deleted
+ Gui::Selection().addSelectionGate(new ShapeSelection(selectionMode, editedObject));
+ selectionMode = RemoveEdge;
+}
+
+void SectionsPanel::onSelectionChanged(const Gui::SelectionChanges& msg)
+{
+ if (selectionMode == None)
+ return;
+
+ if (msg.Type == Gui::SelectionChanges::AddSelection) {
+ checkOpenCommand();
+ if (selectionMode == AppendEdge) {
+ QListWidgetItem* item = new QListWidgetItem(ui->listSections);
+ ui->listSections->addItem(item);
+
+ Gui::SelectionObject sel(msg);
+ QString text = QString::fromLatin1("%1.%2")
+ .arg(QString::fromUtf8(sel.getObject()->Label.getValue()))
+ .arg(QString::fromLatin1(msg.pSubName));
+ item->setText(text);
+
+ QList data;
+ data << QByteArray(msg.pDocName);
+ data << QByteArray(msg.pObjectName);
+ data << QByteArray(msg.pSubName);
+ item->setData(Qt::UserRole, data);
+
+ appendCurve(sel.getObject(), msg.pSubName);
+ }
+ else if (selectionMode == RemoveEdge) {
+ Gui::SelectionObject sel(msg);
+ QList data;
+ data << QByteArray(msg.pDocName);
+ data << QByteArray(msg.pObjectName);
+ data << QByteArray(msg.pSubName);
+
+ // only the three first elements must match
+ for (int i=0; ilistSections->count(); i++) {
+ QListWidgetItem* item = ui->listSections->item(i);
+ QList userdata = item->data(Qt::UserRole).toList();
+ if (userdata.mid(0,3) == data) {
+ ui->listSections->takeItem(i);
+ delete item;
+ break;
+ }
+ }
+
+ removeCurve(sel.getObject(), msg.pSubName);
+ }
+
+ editedObject->recomputeFeature();
+ QTimer::singleShot(50, this, SLOT(clearSelection()));
+ }
+}
+
+void SectionsPanel::onDeleteEdge()
+{
+ int row = ui->listSections->currentRow();
+ QListWidgetItem* item = ui->listSections->takeItem(row);
+ if (item) {
+ checkOpenCommand();
+ QList data;
+ data = item->data(Qt::UserRole).toList();
+ delete item;
+
+ App::Document* doc = App::GetApplication().getDocument(data[0].toByteArray());
+ App::DocumentObject* obj = doc ? doc->getObject(data[1].toByteArray()) : nullptr;
+ std::string sub = data[2].toByteArray().constData();
+
+ removeCurve(obj, sub);
+ editedObject->recomputeFeature();
+ }
+}
+
+void SectionsPanel::onIndexesMoved()
+{
+ QAbstractItemModel* model = qobject_cast(sender());
+ if (!model)
+ return;
+
+ std::vector objects;
+ std::vector element;
+
+ int rows = model->rowCount();
+ for (int i = 0; i < rows; i++) {
+ QModelIndex index = model->index(i, 0);
+ QList data;
+ data = index.data(Qt::UserRole).toList();
+
+ App::Document* doc = App::GetApplication().getDocument(data[0].toByteArray());
+ App::DocumentObject* obj = doc ? doc->getObject(data[1].toByteArray()) : nullptr;
+ std::string sub = data[2].toByteArray().constData();
+
+ objects.push_back(obj);
+ element.push_back(sub);
+ }
+
+ editedObject->NSections.setValues(objects, element);
+ editedObject->recomputeFeature();
+}
+
+void SectionsPanel::appendCurve(App::DocumentObject* obj, const std::string& subname)
+{
+ auto objects = editedObject->NSections.getValues();
+ objects.push_back(obj);
+ auto element = editedObject->NSections.getSubValues();
+ element.push_back(subname);
+ editedObject->NSections.setValues(objects, element);
+
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), true);
+}
+
+void SectionsPanel::removeCurve(App::DocumentObject* obj, const std::string& subname)
+{
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), false);
+
+ auto objects = editedObject->NSections.getValues();
+ auto element = editedObject->NSections.getSubValues();
+
+ auto it = objects.begin();
+ auto jt = element.begin();
+ for (; it != objects.end() && jt != element.end(); ++it, ++jt) {
+ if (*it == obj && *jt == subname) {
+ objects.erase(it);
+ element.erase(jt);
+ editedObject->NSections.setValues(objects, element);
+ break;
+ }
+ }
+ this->vp->highlightReferences(ViewProviderSections::Edge,
+ editedObject->NSections.getSubListValues(), true);
+
+}
+
+// ----------------------------------------------------------------------------
+
+TaskSections::TaskSections(ViewProviderSections* vp, Surface::Sections* obj)
+{
+ // first task box
+ widget1 = new SectionsPanel(vp, obj);
+ Gui::TaskView::TaskBox* taskbox1 = new Gui::TaskView::TaskBox(
+ Gui::BitmapFactory().pixmap("BezSurf"),
+ widget1->windowTitle(), true, 0);
+ taskbox1->groupLayout()->addWidget(widget1);
+ Content.push_back(taskbox1);
+}
+
+TaskSections::~TaskSections()
+{
+ // automatically deleted in the sub-class
+}
+
+void TaskSections::setEditedObject(Surface::Sections* obj)
+{
+ widget1->setEditedObject(obj);
+}
+
+void TaskSections::open()
+{
+ widget1->open();
+}
+
+bool TaskSections::accept()
+{
+ bool ok = widget1->accept();
+ if (ok) {
+ Gui::Command::commitCommand();
+ Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()");
+ Gui::Command::updateActive();
+ }
+
+ return ok;
+}
+
+bool TaskSections::reject()
+{
+ bool ok = widget1->reject();
+ if (ok) {
+ Gui::Command::abortCommand();
+ Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()");
+ Gui::Command::updateActive();
+ }
+
+ return ok;
+}
+
+}
+
+#include "moc_TaskSections.cpp"
diff --git a/src/Mod/Surface/Gui/TaskSections.h b/src/Mod/Surface/Gui/TaskSections.h
new file mode 100644
index 000000000000..03f1c5635cbf
--- /dev/null
+++ b/src/Mod/Surface/Gui/TaskSections.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ * Copyright (c) 2020 Werner Mayer *
+ * *
+ * This file is part of the FreeCAD CAx development system. *
+ * *
+ * This library is free software; you can redistribute it and/or *
+ * modify it under the terms of the GNU Library General Public *
+ * License as published by the Free Software Foundation; either *
+ * version 2 of the License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; see the file COPYING.LIB. If not, *
+ * write to the Free Software Foundation, Inc., 59 Temple Place, *
+ * Suite 330, Boston, MA 02111-1307, USA *
+ * *
+ ***************************************************************************/
+
+#ifndef SURFACEGUI_TASKSECTIONS_H
+#define SURFACEGUI_TASKSECTIONS_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class QListWidgetItem;
+
+namespace SurfaceGui
+{
+
+class Ui_Sections;
+
+class ViewProviderSections : public PartGui::ViewProviderSpline
+{
+ PROPERTY_HEADER(SurfaceGui::ViewProviderSections);
+ typedef std::vector References;
+
+public:
+ enum ShapeType {Vertex, Edge, Face};
+ virtual void setupContextMenu(QMenu*, QObject*, const char*);
+ virtual bool setEdit(int ModNum);
+ virtual void unsetEdit(int ModNum);
+ QIcon getIcon(void) const;
+ void highlightReferences(ShapeType type, const References& refs, bool on);
+};
+
+class SectionsPanel : public QWidget,
+ public Gui::SelectionObserver,
+ public Gui::DocumentObserver
+{
+ Q_OBJECT
+
+protected:
+ class ShapeSelection;
+ enum SelectionMode { None, AppendEdge, RemoveEdge };
+ SelectionMode selectionMode;
+ Surface::Sections* editedObject;
+ bool checkCommand;
+
+private:
+ std::unique_ptr ui;
+ ViewProviderSections* vp;
+
+public:
+ SectionsPanel(ViewProviderSections* vp, Surface::Sections* obj);
+ ~SectionsPanel();
+
+ void open();
+ void checkOpenCommand();
+ bool accept();
+ bool reject();
+ void setEditedObject(Surface::Sections* obj);
+
+protected:
+ void changeEvent(QEvent *e);
+ virtual void onSelectionChanged(const Gui::SelectionChanges& msg);
+ /** Notifies on undo */
+ virtual void slotUndoDocument(const Gui::Document& Doc);
+ /** Notifies on redo */
+ virtual void slotRedoDocument(const Gui::Document& Doc);
+ /** Notifies when the object is about to be removed. */
+ virtual void slotDeletedObject(const Gui::ViewProviderDocumentObject& Obj);
+
+private Q_SLOTS:
+ void on_buttonEdgeAdd_clicked();
+ void on_buttonEdgeRemove_clicked();
+ void onDeleteEdge(void);
+ void clearSelection();
+ void onIndexesMoved();
+
+private:
+ void appendCurve(App::DocumentObject*, const std::string& subname);
+ void removeCurve(App::DocumentObject*, const std::string& subname);
+};
+
+class TaskSections : public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+
+public:
+ TaskSections(ViewProviderSections* vp, Surface::Sections* obj);
+ ~TaskSections();
+ void setEditedObject(Surface::Sections* obj);
+
+public:
+ void open();
+ bool accept();
+ bool reject();
+
+ virtual QDialogButtonBox::StandardButtons getStandardButtons() const
+ { return QDialogButtonBox::Ok | QDialogButtonBox::Cancel; }
+
+private:
+ SectionsPanel* widget1;
+};
+
+} //namespace SurfaceGui
+
+#endif // SURFACEGUI_TASKSECTIONS_H
diff --git a/src/Mod/Surface/Gui/TaskSections.ui b/src/Mod/Surface/Gui/TaskSections.ui
new file mode 100644
index 000000000000..4a32798c86d6
--- /dev/null
+++ b/src/Mod/Surface/Gui/TaskSections.ui
@@ -0,0 +1,83 @@
+
+
+ SurfaceGui::Sections
+
+
+
+ 0
+ 0
+ 293
+ 443
+
+
+
+ Sections
+
+
+ -
+
+
+ Sections
+
+
+
-
+
+
+ <html><head/><body><p>List can be reordered by dragging</p></body></html>
+
+
+ QAbstractItemView::InternalMove
+
+
+
+ -
+
+
-
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ Add Edge
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Remove Edge
+
+
+
+
+
+ -
+
+
+ Status messages
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Mod/Surface/Gui/Workbench.cpp b/src/Mod/Surface/Gui/Workbench.cpp
index 85db1ea5e90e..ad46792fa649 100644
--- a/src/Mod/Surface/Gui/Workbench.cpp
+++ b/src/Mod/Surface/Gui/Workbench.cpp
@@ -55,7 +55,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const
*surface << "Surface_CurveOnMesh"
<< "Surface_ExtendFace"
<< "Surface_Filling"
- << "Surface_GeomFillSurface";
+ << "Surface_GeomFillSurface"
+ << "Surface_Sections";
/* *surface << "Surface_Filling";
*surface << "Surface_Cut";*/