diff --git a/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp b/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp
index b75ffa166d..5bd034c4eb 100644
--- a/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp
+++ b/src/Mod/MeshPart/Gui/AppMeshPartGui.cpp
@@ -32,6 +32,7 @@
#include
#include
#include
+#include "CurveOnMesh.h"
#include "Workbench.h"
// use a different name to CreateCommand()
@@ -79,7 +80,8 @@ PyMOD_INIT_FUNC(MeshPartGui)
// instantiating the commands
CreateMeshPartCommands();
- MeshPartGui::Workbench::init();
+ MeshPartGui::Workbench ::init();
+ MeshPartGui::ViewProviderCurveOnMesh ::init();
// add resources and reloads the translators
loadMeshPartResource();
diff --git a/src/Mod/MeshPart/Gui/CMakeLists.txt b/src/Mod/MeshPart/Gui/CMakeLists.txt
index 5a10cdae99..112af4999b 100644
--- a/src/Mod/MeshPart/Gui/CMakeLists.txt
+++ b/src/Mod/MeshPart/Gui/CMakeLists.txt
@@ -33,12 +33,15 @@ set(MeshPartGui_LIBS
)
set(MeshPartGui_MOC_HDRS
+ CurveOnMesh.h
+ TaskCurveOnMesh.h
Tessellation.h
)
fc_wrap_cpp(MeshPartGui_MOC_SRCS ${MeshPartGui_MOC_HDRS})
SOURCE_GROUP("Moc" FILES ${MeshPartGui_MOC_SRCS})
set(MeshPartGui_UIC_SRCS
+ TaskCurveOnMesh.ui
Tessellation.ui
)
@@ -55,9 +58,14 @@ SET(MeshPartGui_SRCS
${MeshPartGui_UIC_HDRS}
AppMeshPartGui.cpp
Command.cpp
+ CurveOnMesh.cpp
+ CurveOnMesh.h
Resources/MeshPart.qrc
PreCompiled.cpp
PreCompiled.h
+ TaskCurveOnMesh.ui
+ TaskCurveOnMesh.cpp
+ TaskCurveOnMesh.h
Tessellation.ui
Tessellation.cpp
Tessellation.h
diff --git a/src/Mod/MeshPart/Gui/Command.cpp b/src/Mod/MeshPart/Gui/Command.cpp
index 70145692d9..28bb7efabb 100644
--- a/src/Mod/MeshPart/Gui/Command.cpp
+++ b/src/Mod/MeshPart/Gui/Command.cpp
@@ -29,12 +29,18 @@
#include
+#include
+#include
#include
#include
#include
+#include
#include
#include
+#include
+#include
#include "Tessellation.h"
+#include "TaskCurveOnMesh.h"
using namespace std;
@@ -230,6 +236,43 @@ bool CmdMeshPartSection::isActive(void)
return true;
}
+DEF_STD_CMD_A(CmdMeshPartCurveOnMesh)
+
+CmdMeshPartCurveOnMesh::CmdMeshPartCurveOnMesh()
+ : Command("MeshPart_CurveOnMesh")
+{
+ sAppModule = "MeshPart";
+ sGroup = QT_TR_NOOP("Mesh");
+ sMenuText = QT_TR_NOOP("Curve on mesh...");
+ sToolTipText = QT_TR_NOOP("Curve on mesh");
+ sWhatsThis = "MeshPart_CurveOnMesh";
+ sStatusTip = sToolTipText;
+}
+
+void CmdMeshPartCurveOnMesh::activated(int)
+{
+ Gui::Document* doc = getActiveGuiDocument();
+ std::list mdis = doc->getMDIViewsOfType(Gui::View3DInventor::getClassTypeId());
+ if (mdis.empty()) {
+ return;
+ }
+
+ Gui::Control().showDialog(new MeshPartGui::TaskCurveOnMesh(static_cast(mdis.front())));
+}
+
+bool CmdMeshPartCurveOnMesh::isActive(void)
+{
+ if (Gui::Control().activeDialog())
+ return false;
+
+ // Check for the selected mesh feature (all Mesh types)
+ App::Document* doc = App::GetApplication().getActiveDocument();
+ if (doc && doc->countObjectsOfType(Mesh::Feature::getClassTypeId()) > 0)
+ return true;
+
+ return false;
+}
+
void CreateMeshPartCommands(void)
{
@@ -237,4 +280,5 @@ void CreateMeshPartCommands(void)
rcCmdMgr.addCommand(new CmdMeshPartMesher());
rcCmdMgr.addCommand(new CmdMeshPartTrimByPlane());
rcCmdMgr.addCommand(new CmdMeshPartSection());
+ rcCmdMgr.addCommand(new CmdMeshPartCurveOnMesh());
}
diff --git a/src/Mod/MeshPart/Gui/CurveOnMesh.cpp b/src/Mod/MeshPart/Gui/CurveOnMesh.cpp
new file mode 100644
index 0000000000..d8fbfdff9e
--- /dev/null
+++ b/src/Mod/MeshPart/Gui/CurveOnMesh.cpp
@@ -0,0 +1,616 @@
+/***************************************************************************
+ * 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"
+
+#ifndef _PreComp_
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+#endif
+
+#include "CurveOnMesh.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef HAVE_ACOSH
+#define HAVE_ACOSH
+#endif
+#ifndef HAVE_ASINH
+#define HAVE_ASINH
+#endif
+#ifndef HAVE_ATANH
+#define HAVE_ATANH
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* XPM */
+static const char *cursor_curveonmesh[]={
+"32 32 3 1",
+"+ c white",
+"# c red",
+". c None",
+"......+.........................",
+"......+.........................",
+"......+.........................",
+"......+.........................",
+"......+.........................",
+"................................",
+"+++++...+++++...................",
+"................................",
+"......+...............###.......",
+"......+...............#.#.......",
+"......+...............###.......",
+"......+..............#..#.......",
+"......+.............#....#......",
+"....................#.+..#......",
+"..................+#+..+..#...+.",
+"................++#.....+.#..+..",
+"......+........+..#......++#+...",
+".......+......+..#.........#....",
+"........++..++..#..........###..",
+"..........++....#..........#.#..",
+"......#........#...........###..",
+".......#......#.................",
+"........#.....#.................",
+".........#...#..................",
+"..........###...................",
+"..........#.#...................",
+"..........###...................",
+"................................",
+"................................",
+"................................",
+"................................",
+"................................"};
+
+using namespace MeshPartGui;
+
+PROPERTY_SOURCE(MeshPartGui::ViewProviderCurveOnMesh, Gui::ViewProviderDocumentObject)
+
+ViewProviderCurveOnMesh::ViewProviderCurveOnMesh()
+{
+ // the lines
+ pcCoords = new SoCoordinate3;
+ pcCoords->ref();
+ pcCoords->point.setNum(0);
+
+ pcLinesStyle = new SoDrawStyle;
+ pcLinesStyle->style = SoDrawStyle::LINES;
+ pcLinesStyle->lineWidth = 3;
+ pcLinesStyle->ref();
+
+ SoGroup* pcLineRoot = new SoSeparator();
+ pcLineRoot->addChild(pcLinesStyle);
+ SoBaseColor * linecol = new SoBaseColor;
+ linecol->rgb.setValue(1.0f, 1.0f, 0.0f);
+ pcLineRoot->addChild(linecol);
+ pcLineRoot->addChild(pcCoords);
+ pcLineRoot->addChild(new SoLineSet);
+
+ // the nodes
+ pcNodes = new SoCoordinate3;
+ pcNodes->ref();
+ pcNodes->point.setNum(0);
+
+ pcPointStyle = new SoDrawStyle;
+ pcPointStyle->style = SoDrawStyle::POINTS;
+ pcPointStyle->pointSize = 15;
+ pcPointStyle->ref();
+
+ SoGroup* pcPointRoot = new SoSeparator();
+ pcPointRoot->addChild(pcPointStyle);
+ SoBaseColor * pointcol = new SoBaseColor;
+ pointcol->rgb.setValue(1.0f, 0.5f, 0.0f);
+ pcPointRoot->addChild(pointcol);
+ pcPointRoot->addChild(pcNodes);
+ pcPointRoot->addChild(new SoPointSet);
+
+ SoGroup* group = new SoGroup;
+ group->addChild(pcLineRoot);
+ group->addChild(pcPointRoot);
+ addDisplayMaskMode(group, "Point");
+}
+
+ViewProviderCurveOnMesh::~ViewProviderCurveOnMesh()
+{
+ pcCoords->unref();
+ pcLinesStyle->unref();
+ pcNodes->unref();
+ pcPointStyle->unref();
+}
+
+void ViewProviderCurveOnMesh::setDisplayMode(const char* ModeName)
+{
+ setDisplayMaskMode(ModeName);
+ ViewProviderDocumentObject::setDisplayMode(ModeName);
+}
+
+void ViewProviderCurveOnMesh::addVertex(const SbVec3f& v)
+{
+ int num = pcNodes->point.getNum();
+ pcNodes->point.set1Value(num, v);
+}
+
+void ViewProviderCurveOnMesh::clearVertex()
+{
+ pcNodes->point.setNum(0);
+}
+
+void ViewProviderCurveOnMesh::setPoints(const std::vector& pts)
+{
+ pcCoords->point.setNum(pts.size());
+ SbVec3f* coords = pcCoords->point.startEditing();
+ int index = 0;
+ for (std::vector::const_iterator it = pts.begin(); it != pts.end(); ++it) {
+ coords[index] = *it;
+ index++;
+ }
+ pcCoords->point.finishEditing();
+}
+
+void ViewProviderCurveOnMesh::clearPoints()
+{
+ pcCoords->point.setNum(0);
+}
+
+// ------------------------------------------------------------------
+
+class CurveOnMeshHandler::Private
+{
+public:
+ struct PickedPoint
+ {
+ unsigned long facet;
+ SbVec3f point;
+ SbVec3f normal;
+ };
+
+ struct ApproxPar
+ {
+ double weight1;
+ double weight2;
+ double weight3;
+ double tol3d;
+ int maxDegree;
+ GeomAbs_Shape cont;
+
+ ApproxPar() {
+ weight1 = 0.2;
+ weight2 = 0.4;
+ weight3 = 0.2;
+ tol3d = 1.0e-2;
+ maxDegree = 5;
+ cont = GeomAbs_C2;
+ }
+ };
+ Private()
+ : wireClosed(false)
+ , distance(1.0)
+ , cosAngle(0.7071) // 45 degree
+ , curve(new ViewProviderCurveOnMesh)
+ , mesh(0)
+ , grid(0)
+ , kernel(0)
+ , viewer(0)
+ , editcursor(QPixmap(cursor_curveonmesh), 7, 7)
+ {
+ }
+ ~Private()
+ {
+ delete curve;
+ delete grid;
+ }
+ static void vertexCallback(void * ud, SoEventCallback * n);
+ std::vector convert(const std::vector& points) const
+ {
+ std::vector pts;
+ pts.reserve(points.size());
+ for (auto it = points.begin(); it != points.end(); ++it) {
+ pts.push_back(Base::convertTo(*it));
+ }
+ return pts;
+ }
+ void createGrid()
+ {
+ Mesh::Feature* mf = static_cast(mesh->getObject());
+ const Mesh::MeshObject& meshObject = mf->Mesh.getValue();
+ MeshCore::MeshAlgorithm alg(meshObject.getKernel());
+ float fAvgLen = alg.GetAverageEdgeLength();
+ grid = new MeshCore::MeshFacetGrid(meshObject.getKernel(), 5.0f * fAvgLen);
+ kernel = &meshObject;
+ }
+ bool projectLineOnMesh(const PickedPoint& pick)
+ {
+ PickedPoint last = pickedPoints.back();
+ std::vector polyline;
+
+ MeshCore::MeshProjection meshProjection(kernel->getKernel());
+ Base::Vector3f v1 = Base::convertTo(last.point);
+ Base::Vector3f v2 = Base::convertTo(pick.point);
+ Base::Vector3f vd = Base::convertTo(viewer->getViewer()->getViewDirection());
+ if (meshProjection.projectLineOnMesh(*grid, v1, last.facet, v2, pick.facet, vd, polyline)) {
+ if (polyline.size() > 1) {
+ if (cutLines.empty()) {
+ cutLines.push_back(polyline);
+ }
+ else {
+ SbVec3f dir1;
+ SbVec3f dir2 = pick.point - last.point;
+ dir2.normalize();
+ std::size_t num = pickedPoints.size();
+ if (num >= 2) {
+ dir1 = pickedPoints[num-1].point - pickedPoints[num-2].point;
+ dir1.normalize();
+ }
+
+ // if the angle between two line segments is greater than the angle
+ // split the curve in this position
+ if (dir1.dot(dir2) < cosAngle) {
+ cutLines.push_back(polyline);
+ }
+ else {
+ std::vector& segm = cutLines.back();
+ segm.insert(segm.end(), polyline.begin()+1, polyline.end());
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ std::vector pickedPoints;
+ std::list > cutLines;
+ bool wireClosed;
+ double distance;
+ double cosAngle;
+ ViewProviderCurveOnMesh* curve;
+ Gui::ViewProviderDocumentObject* mesh;
+ MeshCore::MeshFacetGrid* grid;
+ Base::Reference kernel;
+ QPointer viewer;
+ QCursor editcursor;
+ ApproxPar par;
+};
+
+CurveOnMeshHandler::CurveOnMeshHandler(QObject* parent)
+ : QObject(parent), d_ptr(new Private)
+{
+}
+
+CurveOnMeshHandler::~CurveOnMeshHandler()
+{
+ disableCallback();
+}
+
+void CurveOnMeshHandler::setParameters(int maxDegree, GeomAbs_Shape cont, double tol3d, double angle)
+{
+ d_ptr->par.maxDegree = maxDegree;
+ d_ptr->par.cont = cont;
+ d_ptr->par.tol3d = tol3d;
+ d_ptr->cosAngle = cos(angle);
+}
+
+void CurveOnMeshHandler::onContextMenu()
+{
+ QMenu menu;
+ menu.addAction(tr("Create"), this, SLOT(onCreate()));
+ if (!d_ptr->wireClosed && d_ptr->pickedPoints.size() >= 3) {
+ menu.addAction(tr("Close wire"), this, SLOT(onCloseWire()));
+ }
+ menu.addAction(tr("Clear"), this, SLOT(onClear()));
+ menu.addAction(tr("Cancel"), this, SLOT(onCancel()));
+ menu.exec(QCursor::pos());
+}
+
+void CurveOnMeshHandler::onCreate()
+{
+ for (auto it = d_ptr->cutLines.begin(); it != d_ptr->cutLines.end(); ++it) {
+ std::vector segm = d_ptr->convert(*it);
+ Handle(Geom_BSplineCurve) spline = approximateSpline(segm);
+ if (!spline.IsNull())
+ displaySpline(spline);
+ }
+
+ d_ptr->curve->clearVertex();
+ d_ptr->curve->clearPoints();
+
+ d_ptr->pickedPoints.clear();
+ d_ptr->cutLines.clear();
+ d_ptr->wireClosed = false;
+
+ disableCallback();
+}
+
+void CurveOnMeshHandler::onCloseWire()
+{
+ if (d_ptr->wireClosed || d_ptr->pickedPoints.size() < 3) {
+ return;
+ }
+
+ closeWire();
+}
+
+void CurveOnMeshHandler::onClear()
+{
+ d_ptr->curve->clearVertex();
+ d_ptr->curve->clearPoints();
+
+ d_ptr->pickedPoints.clear();
+ d_ptr->cutLines.clear();
+ d_ptr->wireClosed = false;
+}
+
+void CurveOnMeshHandler::onCancel()
+{
+ d_ptr->curve->clearVertex();
+ d_ptr->curve->clearPoints();
+
+ d_ptr->pickedPoints.clear();
+ d_ptr->cutLines.clear();
+ d_ptr->wireClosed = false;
+
+ disableCallback();
+}
+
+void CurveOnMeshHandler::enableCallback(Gui::View3DInventor* v)
+{
+ if (v && !d_ptr->viewer) {
+ d_ptr->viewer = v;
+ Gui::View3DInventorViewer* view3d = d_ptr->viewer->getViewer();
+ view3d->addEventCallback(SoEvent::getClassTypeId(), Private::vertexCallback, this);
+ view3d->addViewProvider(d_ptr->curve);
+ view3d->setEditing(true);
+
+ view3d->setEditingCursor(d_ptr->editcursor);
+
+ d_ptr->curve->setDisplayMode("Point");
+ }
+}
+
+void CurveOnMeshHandler::disableCallback()
+{
+ if (d_ptr->viewer) {
+ Gui::View3DInventorViewer* view3d = d_ptr->viewer->getViewer();
+ view3d->setEditing(false);
+ view3d->removeViewProvider(d_ptr->curve);
+ view3d->removeEventCallback(SoEvent::getClassTypeId(), Private::vertexCallback, this);
+ }
+ d_ptr->viewer = 0;
+}
+
+std::vector CurveOnMeshHandler::getVertexes() const
+{
+ std::vector pts;
+ pts.reserve(d_ptr->pickedPoints.size());
+ for (std::vector::const_iterator it = d_ptr->pickedPoints.begin(); it != d_ptr->pickedPoints.end(); ++it)
+ pts.push_back(it->point);
+ return pts;
+}
+
+std::vector CurveOnMeshHandler::getPoints() const
+{
+ std::vector pts;
+ for (auto it = d_ptr->cutLines.begin(); it != d_ptr->cutLines.end(); ++it) {
+ std::vector segm = d_ptr->convert(*it);
+ pts.insert(pts.end(), segm.begin(), segm.end());
+ }
+ return pts;
+}
+
+Handle(Geom_BSplineCurve) CurveOnMeshHandler::approximateSpline(const std::vector& points)
+{
+ TColgp_Array1OfPnt pnts(1,points.size());
+ Standard_Integer index = 1;
+ for (std::vector::const_iterator it = points.begin(); it != points.end(); ++it) {
+ float x,y,z;
+ it->getValue(x,y,z);
+ pnts(index++) = gp_Pnt(x,y,z);
+ }
+
+ try {
+ //GeomAPI_PointsToBSpline fit(pnts, 1, 2, GeomAbs_C0, 1.0e-3);
+ //GeomAPI_PointsToBSpline fit(pnts, d_ptr->par.weight1, d_ptr->par.weight2, d_ptr->par.weight3,
+ // d_ptr->par.maxDegree, d_ptr->par.cont, d_ptr->par.tol3d);
+ GeomAPI_PointsToBSpline fit(pnts, 1, d_ptr->par.maxDegree, d_ptr->par.cont, d_ptr->par.tol3d);
+ Handle(Geom_BSplineCurve) spline = fit.Curve();
+ return spline;
+ }
+ catch (...) {
+ return Handle(Geom_BSplineCurve)();
+ }
+}
+
+void CurveOnMeshHandler::approximateEdge(const TopoDS_Edge& edge, double tolerance)
+{
+ BRepMesh_IncrementalMesh(edge, tolerance);
+ TopLoc_Location loc;
+ Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(edge, loc);
+ if (!aPoly.IsNull()) {
+ int numNodes = aPoly->NbNodes();
+ const TColgp_Array1OfPnt& aNodes = aPoly->Nodes();
+ std::vector pts;
+ pts.reserve(numNodes);
+ for (int i=aNodes.Lower(); i<=aNodes.Upper(); i++) {
+ const gp_Pnt& p = aNodes.Value(i);
+ pts.push_back(SbVec3f(static_cast(p.X()),
+ static_cast(p.Y()),
+ static_cast(p.Z())));
+ }
+
+ d_ptr->curve->setPoints(pts);
+ }
+}
+
+void CurveOnMeshHandler::displaySpline(const Handle(Geom_BSplineCurve)& spline)
+{
+ if (d_ptr->viewer) {
+ double u = spline->FirstParameter();
+ double v = spline->LastParameter();
+ BRepBuilderAPI_MakeEdge mkBuilder(spline, u, v);
+ TopoDS_Edge edge = mkBuilder.Edge();
+
+ Gui::View3DInventorViewer* view3d = d_ptr->viewer->getViewer();
+ App::Document* doc = view3d->getDocument()->getDocument();
+ Part::Feature* part = static_cast(doc->addObject("Part::Spline", "Spline"));
+ part->Shape.setValue(edge);
+ }
+}
+
+bool CurveOnMeshHandler::tryCloseWire(const SbVec3f& p) const
+{
+ if (d_ptr->pickedPoints.size() >= 3) {
+ Private::PickedPoint first = d_ptr->pickedPoints.front();
+ // if the distance of the first and last points is small enough (~1mm)
+ // the curve can be closed.
+ float len = (first.point - p).length();
+ if (len < d_ptr->distance) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CurveOnMeshHandler::closeWire()
+{
+ Private::PickedPoint pick = d_ptr->pickedPoints.front();
+ if (d_ptr->projectLineOnMesh(pick)) {
+ d_ptr->curve->setPoints(getPoints());
+ d_ptr->wireClosed = true;
+ }
+}
+
+void CurveOnMeshHandler::Private::vertexCallback(void * ud, SoEventCallback * n)
+{
+ Gui::View3DInventorViewer* view = reinterpret_cast(n->getUserData());
+ const SoEvent* ev = n->getEvent();
+ if (ev->getTypeId() == SoMouseButtonEvent::getClassTypeId()) {
+ // set as handled
+ n->setHandled();
+
+ const SoMouseButtonEvent * mbe = static_cast(ev);
+ if (mbe->getButton() == SoMouseButtonEvent::BUTTON1 && mbe->getState() == SoButtonEvent::DOWN) {
+ const SoPickedPoint * pp = n->getPickedPoint();
+ if (pp) {
+ CurveOnMeshHandler* self = static_cast(ud);
+ if (!self->d_ptr->wireClosed) {
+ Gui::ViewProvider* vp = static_cast(view->getViewProviderByPath(pp->getPath()));
+ if (vp && vp->getTypeId().isDerivedFrom(MeshGui::ViewProviderMesh::getClassTypeId())) {
+ MeshGui::ViewProviderMesh* mesh = static_cast(vp);
+ const SoDetail* detail = pp->getDetail();
+ if (detail && detail->getTypeId() == SoFaceDetail::getClassTypeId()) {
+ // get the mesh and build a grid
+ if (!self->d_ptr->mesh) {
+ self->d_ptr->mesh = mesh;
+ self->d_ptr->createGrid();
+ }
+ else if (self->d_ptr->mesh != mesh) {
+ Gui::getMainWindow()->statusBar()->showMessage(
+ tr("Wrong mesh picked"));
+ return;
+ }
+
+ const SbVec3f& p = pp->getPoint();
+ const SbVec3f& n = pp->getNormal();
+
+ Private::PickedPoint pick;
+ pick.facet = static_cast(detail)->getFaceIndex();
+ pick.point = p;
+ pick.normal = n;
+
+ if (self->d_ptr->pickedPoints.empty()) {
+ self->d_ptr->pickedPoints.push_back(pick);
+ self->d_ptr->curve->addVertex(p);
+ }
+ else {
+ // check to auto-complete the curve
+ if (self->tryCloseWire(p)) {
+ self->closeWire();
+ }
+ else if (self->d_ptr->projectLineOnMesh(pick)) {
+ self->d_ptr->curve->setPoints(self->getPoints());
+ self->d_ptr->pickedPoints.push_back(pick);
+ self->d_ptr->curve->addVertex(p);
+ }
+ }
+ }
+ }
+ // try to 'complete' the curve
+ else if (vp && vp->getTypeId().isDerivedFrom(ViewProviderCurveOnMesh::getClassTypeId())) {
+ const SbVec3f& p = pp->getPoint();
+ if (self->tryCloseWire(p)) {
+ self->closeWire();
+ }
+ }
+ }
+ }
+ else {
+ Gui::getMainWindow()->statusBar()->showMessage(
+ tr("No point was picked"));
+ }
+ }
+ else if (mbe->getButton() == SoMouseButtonEvent::BUTTON2 && mbe->getState() == SoButtonEvent::UP) {
+ CurveOnMeshHandler* self = static_cast(ud);
+ QTimer::singleShot(100, self, SLOT(onContextMenu()));
+ }
+ }
+}
+
+#include "moc_CurveOnMesh.cpp"
diff --git a/src/Mod/MeshPart/Gui/CurveOnMesh.h b/src/Mod/MeshPart/Gui/CurveOnMesh.h
new file mode 100644
index 0000000000..d6b7c84237
--- /dev/null
+++ b/src/Mod/MeshPart/Gui/CurveOnMesh.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * 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 *
+ * *
+ ***************************************************************************/
+
+#ifndef MESHPARTGUI_CURVEONMESH_H
+#define MESHPARTGUI_CURVEONMESH_H
+
+#include
+#include
+#include
+#include
+#include
+
+class SbVec3f;
+class SoCoordinate3;
+class SoDrawStyle;
+class TopoDS_Edge;
+
+namespace Gui {
+class View3DInventor;
+class ViewProvider;
+}
+
+namespace MeshPartGui
+{
+
+class ViewProviderCurveOnMesh : public Gui::ViewProviderDocumentObject
+{
+ PROPERTY_HEADER(MeshPartGui::ViewProviderCurveOnMesh);
+
+public:
+ ViewProviderCurveOnMesh();
+ virtual ~ViewProviderCurveOnMesh();
+ void addVertex(const SbVec3f&);
+ void clearVertex();
+ void setPoints(const std::vector&);
+ void clearPoints();
+ void setDisplayMode(const char* ModeName);
+
+private:
+ SoCoordinate3 * pcCoords;
+ SoCoordinate3 * pcNodes;
+ SoDrawStyle * pcPointStyle;
+ SoDrawStyle * pcLinesStyle;
+};
+
+class CurveOnMeshHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ CurveOnMeshHandler(QObject* parent = 0);
+ ~CurveOnMeshHandler();
+ void setParameters(int maxDegree, GeomAbs_Shape cont, double tol3d, double angle);
+ void enableCallback(Gui::View3DInventor* viewer);
+ void disableCallback();
+
+private:
+ Handle(Geom_BSplineCurve) approximateSpline(const std::vector& points);
+ void approximateEdge(const TopoDS_Edge&, double tolerance);
+ void displaySpline(const Handle(Geom_BSplineCurve)&);
+ std::vector getPoints() const;
+ std::vector getVertexes() const;
+ void closeWire();
+ bool tryCloseWire(const SbVec3f&) const;
+
+private Q_SLOTS:
+ void onContextMenu();
+ void onCreate();
+ void onClear();
+ void onCancel();
+ void onCloseWire();
+
+private:
+ class Private;
+ std::unique_ptr d_ptr;
+};
+
+}
+
+#endif // MESHPARTGUI_CURVEONMESH_H
diff --git a/src/Mod/MeshPart/Gui/PreCompiled.h b/src/Mod/MeshPart/Gui/PreCompiled.h
index 26f83b65ee..10c7b54fd8 100644
--- a/src/Mod/MeshPart/Gui/PreCompiled.h
+++ b/src/Mod/MeshPart/Gui/PreCompiled.h
@@ -44,6 +44,7 @@
#endif
#ifdef _MSC_VER
+# pragma warning(disable : 4005)
# pragma warning(disable : 4290)
# pragma warning(disable : 4275)
#endif
diff --git a/src/Mod/MeshPart/Gui/TaskCurveOnMesh.cpp b/src/Mod/MeshPart/Gui/TaskCurveOnMesh.cpp
new file mode 100644
index 0000000000..be2638360c
--- /dev/null
+++ b/src/Mod/MeshPart/Gui/TaskCurveOnMesh.cpp
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * 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 "TaskCurveOnMesh.h"
+#include "ui_TaskCurveOnMesh.h"
+#include "CurveOnMesh.h"
+
+#include
+#include
+#include
+#include
+
+
+using namespace MeshPartGui;
+
+CurveOnMeshWidget::CurveOnMeshWidget(Gui::View3DInventor* view, QWidget* parent)
+ : QWidget(parent)
+ , ui(new Ui_TaskCurveOnMesh())
+ , myCurveHandler(new CurveOnMeshHandler(this))
+ , myView(view)
+{
+ ui->setupUi(this);
+ this->setup();
+}
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+CurveOnMeshWidget::~CurveOnMeshWidget()
+{
+ // no need to delete child widgets, Qt does it all for us
+ delete ui;
+}
+
+void CurveOnMeshWidget::setup()
+{
+ ui->meshTolerance->setValue(0.2);
+ ui->continuity->addItem(QString::fromLatin1("C0"), static_cast(GeomAbs_C0));
+ ui->continuity->addItem(QString::fromLatin1("C1"), static_cast(GeomAbs_C1));
+ ui->continuity->addItem(QString::fromLatin1("C2"), static_cast(GeomAbs_C2));
+ ui->continuity->addItem(QString::fromLatin1("C3"), static_cast(GeomAbs_C3));
+ ui->continuity->setCurrentIndex(2);
+
+ for (int i=0; i<8; i++)
+ ui->maxDegree->addItem(QString::number(i+1));
+ ui->maxDegree->setCurrentIndex(4);
+}
+
+void CurveOnMeshWidget::changeEvent(QEvent *e)
+{
+ if (e->type() == QEvent::LanguageChange) {
+ ui->retranslateUi(this);
+ }
+ else {
+ QWidget::changeEvent(e);
+ }
+}
+
+void CurveOnMeshWidget::on_startButton_clicked()
+{
+ int cont = ui->continuity->itemData(ui->continuity->currentIndex()).toInt();
+ myCurveHandler->setParameters(ui->maxDegree->currentIndex(),
+ static_cast(cont),
+ ui->meshTolerance->value(),
+ ui->splitAngle->value().getValue());
+ myCurveHandler->enableCallback(myView);
+}
+
+void CurveOnMeshWidget::reject()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+TaskCurveOnMesh::TaskCurveOnMesh(Gui::View3DInventor* view)
+{
+ widget = new CurveOnMeshWidget(view);
+ taskbox = new Gui::TaskView::TaskBox(
+ QPixmap(),
+ widget->windowTitle(), true, 0);
+ taskbox->groupLayout()->addWidget(widget);
+ Content.push_back(taskbox);
+}
+
+TaskCurveOnMesh::~TaskCurveOnMesh()
+{
+ // automatically deleted in the sub-class
+}
+
+bool TaskCurveOnMesh::reject()
+{
+ widget->reject();
+ return true;
+}
+
+#include "moc_TaskCurveOnMesh.cpp"
diff --git a/src/Mod/MeshPart/Gui/TaskCurveOnMesh.h b/src/Mod/MeshPart/Gui/TaskCurveOnMesh.h
new file mode 100644
index 0000000000..cc08757663
--- /dev/null
+++ b/src/Mod/MeshPart/Gui/TaskCurveOnMesh.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * 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 *
+ * *
+ ***************************************************************************/
+
+#ifndef MESHPART_GUI_TASKCURVEONMESH_H
+#define MESHPART_GUI_TASKCURVEONMESH_H
+
+#include
+#include
+#include
+
+namespace Gui {
+class View3DInventor;
+}
+
+namespace MeshPartGui
+{
+
+class Ui_TaskCurveOnMesh;
+class CurveOnMeshHandler;
+
+class CurveOnMeshWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CurveOnMeshWidget(Gui::View3DInventor* view, QWidget* parent=0);
+ ~CurveOnMeshWidget();
+
+ void reject();
+
+protected:
+ void changeEvent(QEvent *e);
+ void setup();
+
+private Q_SLOTS:
+ void on_startButton_clicked();
+
+private:
+ Ui_TaskCurveOnMesh* ui;
+ CurveOnMeshHandler* myCurveHandler;
+ QPointer myView;
+};
+
+class TaskCurveOnMesh : public Gui::TaskView::TaskDialog
+{
+ Q_OBJECT
+
+public:
+ TaskCurveOnMesh(Gui::View3DInventor* view);
+ ~TaskCurveOnMesh();
+
+public:
+ bool reject();
+
+ virtual QDialogButtonBox::StandardButtons getStandardButtons() const
+ { return QDialogButtonBox::Close; }
+
+private:
+ CurveOnMeshWidget* widget;
+ Gui::TaskView::TaskBox* taskbox;
+};
+
+} //namespace MeshPartGui
+
+#endif // MESHPART_GUI_TASKCURVEONMESH_H
diff --git a/src/Mod/MeshPart/Gui/TaskCurveOnMesh.ui b/src/Mod/MeshPart/Gui/TaskCurveOnMesh.ui
new file mode 100644
index 0000000000..ae02a77ce8
--- /dev/null
+++ b/src/Mod/MeshPart/Gui/TaskCurveOnMesh.ui
@@ -0,0 +1,168 @@
+
+
+ MeshPartGui::TaskCurveOnMesh
+
+
+
+ 0
+ 0
+ 313
+ 247
+
+
+
+ Curve on mesh
+
+
+ -
+
+
+ Wire
+
+
+
-
+
+
+ Snap tolerance to vertexes
+
+
+
+ -
+
+
+ px
+
+
+ 10
+
+
+
+ -
+
+
+ Split threshold
+
+
+
+ -
+
+
+ deg
+
+
+ 5.000000000000000
+
+
+ 180.000000000000000
+
+
+ 45.000000000000000
+
+
+
+
+
+
+ -
+
+
+ Spline Approximation
+
+
+
-
+
+
+ Tolerance to mesh
+
+
+
+ -
+
+
+ 3
+
+
+ 0.001000000000000
+
+
+ 10.000000000000000
+
+
+ 0.010000000000000
+
+
+ 0.010000000000000
+
+
+
+ -
+
+
+ Continuity
+
+
+
+ -
+
+
+ Maximum curve degree
+
+
+
+ -
+
+
+ -1
+
+
+
+ -
+
+
+ -1
+
+
+
+
+
+
+ -
+
+
+ Start
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 211
+ 20
+
+
+
+
+
+
+
+
+ Gui::QuantitySpinBox
+ QWidget
+
+
+
+
+ spinBox
+ splitAngle
+ meshTolerance
+ continuity
+ maxDegree
+ startButton
+
+
+
+
diff --git a/src/Mod/Surface/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp
index e0943bb1a4..24b305e9d0 100644
--- a/src/Mod/Surface/Gui/Command.cpp
+++ b/src/Mod/Surface/Gui/Command.cpp
@@ -180,10 +180,45 @@ void CmdSurfaceGeomFillSurface::activated(int iMsg)
doCommand(Doc, "Gui.ActiveDocument.setEdit('%s',0)", FeatName.c_str());
}
+
+DEF_STD_CMD_A(CmdSurfaceCurveOnMesh)
+
+CmdSurfaceCurveOnMesh::CmdSurfaceCurveOnMesh()
+ : Command("Surface_CurveOnMesh")
+{
+ sAppModule = "MeshPart";
+ sGroup = QT_TR_NOOP("Surface");
+ sMenuText = QT_TR_NOOP("Curve on mesh...");
+ sToolTipText = QT_TR_NOOP("Curve on mesh");
+ sWhatsThis = "Surface_CurveOnMesh";
+ sStatusTip = sToolTipText;
+}
+
+void CmdSurfaceCurveOnMesh::activated(int)
+{
+ doCommand(Doc,"import MeshPartGui, FreeCADGui\n"
+ "FreeCADGui.runCommand('MeshPart_CurveOnMesh')\n");
+}
+
+bool CmdSurfaceCurveOnMesh::isActive(void)
+{
+ if (Gui::Control().activeDialog())
+ return false;
+
+ // Check for the selected mesh feature (all Mesh types)
+ Base::Type meshType = Base::Type::fromName("Mesh::Feature");
+ App::Document* doc = App::GetApplication().getActiveDocument();
+ if (doc && doc->countObjectsOfType(meshType) > 0)
+ return true;
+
+ return false;
+}
+
void CreateSurfaceCommands(void)
{
Gui::CommandManager &rcCmdMgr = Gui::Application::Instance->commandManager();
/* rcCmdMgr.addCommand(new CmdSurfaceFilling());
rcCmdMgr.addCommand(new CmdSurfaceCut());*/
rcCmdMgr.addCommand(new CmdSurfaceGeomFillSurface());
+ rcCmdMgr.addCommand(new CmdSurfaceCurveOnMesh());
}
diff --git a/src/Mod/Surface/Gui/SurfaceFilling.cpp b/src/Mod/Surface/Gui/SurfaceFilling.cpp
index 11db015389..bd29d100c6 100644
--- a/src/Mod/Surface/Gui/SurfaceFilling.cpp
+++ b/src/Mod/Surface/Gui/SurfaceFilling.cpp
@@ -146,7 +146,7 @@ void ViewProviderGeomFillSurface::highlightReferences(bool on)
for (auto jt : it.second) {
std::size_t idx = static_cast(std::stoi(jt.substr(4)) - 1);
- assert (idx >= 0 && idx < colors.size());
+ assert (idx < colors.size());
colors[idx] = App::Color(1.0,0.0,1.0); // magenta
}
diff --git a/src/Mod/Surface/Gui/Workbench.cpp b/src/Mod/Surface/Gui/Workbench.cpp
index 17a241d25e..814c4189b8 100644
--- a/src/Mod/Surface/Gui/Workbench.cpp
+++ b/src/Mod/Surface/Gui/Workbench.cpp
@@ -52,7 +52,8 @@ Gui::MenuItem* Workbench::setupMenuBar() const
Gui::MenuItem* surface = new Gui::MenuItem;
root->insertItem( item, surface );
surface->setCommand("Surface");
- *surface << "Surface_GeomFillSurface";
+ *surface << "Surface_CurveOnMesh"
+ << "Surface_GeomFillSurface";
/* *surface << "Surface_Filling";
*surface << "Surface_Cut";*/