From 48a6bca7d8e150791dc042a9dacec7d5817b1d26 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 19 Apr 2017 23:30:15 +0200 Subject: [PATCH] project polyline on mesh and create edge --- src/Mod/MeshPart/Gui/AppMeshPartGui.cpp | 4 +- src/Mod/MeshPart/Gui/CMakeLists.txt | 8 + src/Mod/MeshPart/Gui/Command.cpp | 44 ++ src/Mod/MeshPart/Gui/CurveOnMesh.cpp | 616 +++++++++++++++++++++++ src/Mod/MeshPart/Gui/CurveOnMesh.h | 99 ++++ src/Mod/MeshPart/Gui/PreCompiled.h | 1 + src/Mod/MeshPart/Gui/TaskCurveOnMesh.cpp | 118 +++++ src/Mod/MeshPart/Gui/TaskCurveOnMesh.h | 84 ++++ src/Mod/MeshPart/Gui/TaskCurveOnMesh.ui | 168 +++++++ src/Mod/Surface/Gui/Command.cpp | 35 ++ src/Mod/Surface/Gui/SurfaceFilling.cpp | 2 +- src/Mod/Surface/Gui/Workbench.cpp | 3 +- 12 files changed, 1179 insertions(+), 3 deletions(-) create mode 100644 src/Mod/MeshPart/Gui/CurveOnMesh.cpp create mode 100644 src/Mod/MeshPart/Gui/CurveOnMesh.h create mode 100644 src/Mod/MeshPart/Gui/TaskCurveOnMesh.cpp create mode 100644 src/Mod/MeshPart/Gui/TaskCurveOnMesh.h create mode 100644 src/Mod/MeshPart/Gui/TaskCurveOnMesh.ui 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 +
Gui/QuantitySpinBox.h
+
+
+ + 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";*/