From 76b66159b3a5a46dcf8cecc5c39eef6a25af853d Mon Sep 17 00:00:00 2001 From: looooo Date: Wed, 11 Oct 2017 23:38:12 +0200 Subject: [PATCH] MeshFlattening: add function to unwrap face --- CMakeLists.txt | 14 +++ src/Mod/Mesh/Gui/Workbench.cpp | 2 +- src/Mod/Mesh/InitGui.py | 8 +- src/Mod/MeshPart/App/CMakeLists.txt | 35 +++--- src/Mod/MeshPart/App/MeshFlattening.cpp | 6 +- src/Mod/MeshPart/App/MeshFlattening.h | 2 +- .../MeshPart/App/MeshFlatteningLscmRelax.cpp | 6 +- .../MeshPart/App/MeshFlatteningLscmRelax.h | 2 +- src/Mod/MeshPart/App/MeshFlatteningNurbs.cpp | 119 +++++++++++++++++- src/Mod/MeshPart/App/MeshFlatteningNurbs.h | 25 +++- src/Mod/MeshPart/App/MeshFlatteningPy.cpp | 70 ++++++++--- src/Mod/MeshPart/Gui/MeshFlatteningCommand.py | 53 ++++++-- 12 files changed, 279 insertions(+), 63 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba018b06dde0..d040104f0786 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,6 +587,20 @@ endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if(FREECAD_USE_PCL) find_package(PCL REQUIRED COMPONENTS common kdtree features surface io filters segmentation sample_consensus) endif(FREECAD_USE_PCL) + +# -------------------------------- PyBind11 ----------------------------- +EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c + "import pybind11; print(bool(pybind11))" + OUTPUT_VARIABLE PYBIND11_FOUND OUTPUT_STRIP_TRAILING_WHITESPACE ) + +EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c + "import pybind11; print(pybind11.get_include())" + OUTPUT_VARIABLE PYBIND11_INCLUDE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE ) + +if (PYBIND11_FOUND) + message(STATUS "successfully found pybind11") + message(STATUS "pybind11 include dir is: " ${PYBIND11_INCLUDE_DIR}) +endif() # -------------------------------- Boost -------------------------------- diff --git a/src/Mod/Mesh/Gui/Workbench.cpp b/src/Mod/Mesh/Gui/Workbench.cpp index 3545df21351a..89eece037ab3 100644 --- a/src/Mod/Mesh/Gui/Workbench.cpp +++ b/src/Mod/Mesh/Gui/Workbench.cpp @@ -193,7 +193,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Mesh_Merge" << "Mesh_PolySelect" << "Mesh_PolyCut" << "Mesh_PolySplit" << "Mesh_PolySegm" << "Mesh_PolyTrim" << "Separator" << "Mesh_TrimByPlane" << "Mesh_SectionByPlane" << "Mesh_Segmentation" - << "Mesh_VertexCurvature" << "CreateFlatMesh"; + << "Mesh_VertexCurvature" << "CreateFlatMesh" << "CreateFlatFace"; return root; } diff --git a/src/Mod/Mesh/InitGui.py b/src/Mod/Mesh/InitGui.py index 51c683f5e49f..0e102ec64a69 100644 --- a/src/Mod/Mesh/InitGui.py +++ b/src/Mod/Mesh/InitGui.py @@ -39,8 +39,12 @@ def __init__(self): def Initialize(self): import Mesh import MeshGui - import MeshFlatteningCommand - + try: + import flatmesh + import MeshFlatteningCommand + except ImportError as e: + import FreeCAD + FreeCAD.Console.PrintLog((str(e))) def GetClassName(self): return "MeshGui::Workbench" diff --git a/src/Mod/MeshPart/App/CMakeLists.txt b/src/Mod/MeshPart/App/CMakeLists.txt index 40931c8fe836..496cfebcb02b 100644 --- a/src/Mod/MeshPart/App/CMakeLists.txt +++ b/src/Mod/MeshPart/App/CMakeLists.txt @@ -81,24 +81,25 @@ SET_PYTHON_PREFIX_SUFFIX(MeshPart) INSTALL(TARGETS MeshPart DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -################################ flat mesh ############################### -SET(FLATMESH_SRCS - MeshFlatteningPy.cpp - MeshFlattening.cpp - MeshFlattening.h - MeshFlatteningNurbs.h - MeshFlatteningNurbs.cpp - MeshFlatteningLscmRelax.h - MeshFlatteningLscmRelax.cpp -) +if (PYBIND11_FOUND) + ################################ flat mesh ############################### + SET(FLATMESH_SRCS + MeshFlatteningPy.cpp + MeshFlattening.cpp + MeshFlattening.h + MeshFlatteningNurbs.h + MeshFlatteningNurbs.cpp + MeshFlatteningLscmRelax.h + MeshFlatteningLscmRelax.cpp + ) -add_library(flatmesh SHARED ${FLATMESH_SRCS}) -SET_PYTHON_PREFIX_SUFFIX(flatmesh) -target_link_libraries(flatmesh ${PYTHON_LIBRARIES} ${MeshPart_LIBS}) + add_library(flatmesh SHARED ${FLATMESH_SRCS}) + SET_PYTHON_PREFIX_SUFFIX(flatmesh) + target_link_libraries(flatmesh ${PYTHON_LIBRARIES} ${MeshPart_LIBS}) -SET_BIN_DIR(flatmesh flatmesh /Mod/MeshPart) -install(TARGETS flatmesh DESTINATION ${CMAKE_INSTALL_LIBDIR}) -############################################################################ + SET_BIN_DIR(flatmesh flatmesh /Mod/MeshPart) + install(TARGETS flatmesh DESTINATION ${CMAKE_INSTALL_LIBDIR}) + ############################################################################ +endif() diff --git a/src/Mod/MeshPart/App/MeshFlattening.cpp b/src/Mod/MeshPart/App/MeshFlattening.cpp index 3125026f7615..a4fcb6f51b32 100644 --- a/src/Mod/MeshPart/App/MeshFlattening.cpp +++ b/src/Mod/MeshPart/App/MeshFlattening.cpp @@ -169,13 +169,13 @@ FaceUnwrapper::FaceUnwrapper(const TopoDS_Face& face) } } -void FaceUnwrapper::findFlatNodes() +void FaceUnwrapper::findFlatNodes(int steps, double val) { std::vector fixed_pins; //TODO: INPUT LscmRelax mesh_flattener(this->xyz_nodes.transpose(), this->tris.transpose(), fixed_pins); mesh_flattener.lscm(); - for (int j=0; j<9; j++) - mesh_flattener.relax(0.9); + for (int j=0; jze_nodes = mesh_flattener.flat_vertices.transpose(); } diff --git a/src/Mod/MeshPart/App/MeshFlattening.h b/src/Mod/MeshPart/App/MeshFlattening.h index 75a641fb2a99..d1f4671dfe56 100644 --- a/src/Mod/MeshPart/App/MeshFlattening.h +++ b/src/Mod/MeshPart/App/MeshFlattening.h @@ -62,7 +62,7 @@ class FaceUnwrapper{ public: FaceUnwrapper(const TopoDS_Face & face); FaceUnwrapper(ColMat xyz_nodes, ColMat tris); - void findFlatNodes(); + void findFlatNodes(int steps, double val); ColMat interpolateFlatFace(const TopoDS_Face& face); std::vector> getFlatBoundaryNodes(); diff --git a/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.cpp b/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.cpp index 471d720b70b6..3133ee8696b8 100644 --- a/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.cpp +++ b/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.cpp @@ -23,6 +23,7 @@ #include "MeshFlatteningLscmRelax.h" #include +#include #include #include #include @@ -278,10 +279,9 @@ void LscmRelax::relax(double weight) // rhs += K_g * Eigen::VectorXd::Ones(K_g.rows()); // solve linear system (privately store the value for guess in next step) - Eigen::ConjugateGradient solver; - solver.setTolerance(0.0000001); + Eigen::SimplicialLDLT solver; solver.compute(K_g); - this->sol = solver.solveWithGuess(-rhs, this->sol); + this->sol = solver.solve(-rhs); this->set_shift(this->sol.head(this->vertices.cols() * 2) * weight); this->set_q_l_m(); } diff --git a/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.h b/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.h index 7795f6c7c0a8..c6bcccf8908e 100644 --- a/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.h +++ b/src/Mod/MeshPart/App/MeshFlatteningLscmRelax.h @@ -88,7 +88,7 @@ class LscmRelax{ ColMat rhs; Eigen::MatrixXd MATRIX; - double nue=0.0; + double nue=0.9; double elasticity=1.; void lscm(); diff --git a/src/Mod/MeshPart/App/MeshFlatteningNurbs.cpp b/src/Mod/MeshPart/App/MeshFlatteningNurbs.cpp index 7604e5e71f56..452803c3c1f6 100644 --- a/src/Mod/MeshPart/App/MeshFlatteningNurbs.cpp +++ b/src/Mod/MeshPart/App/MeshFlatteningNurbs.cpp @@ -25,6 +25,7 @@ #include #include "math.h" + namespace nurbs{ double divide(double a, double b) @@ -35,6 +36,28 @@ double divide(double a, double b) return a / b; } +Eigen::VectorXd NurbsBase1D::getKnotSequence(double u_min, double u_max, int u_deg, int num_u_poles) +{ + // boarder poles are on the surface + std::vector u_knots; + for (int i=0; i < u_deg; i++) + u_knots.push_back(u_min); + for (int i=0; i < num_u_poles; i++) + u_knots.push_back(u_min + (u_max - u_min) * i / (num_u_poles - 1)); + for (int i=0; i < u_deg; i++) + u_knots.push_back(u_max); + return Eigen::Map(u_knots.data(), u_knots.size()); +} + +Eigen::VectorXd NurbsBase1D::getWeightList(Eigen::VectorXd knots, int u_deg) +{ + Eigen::VectorXd weights; + weights.resize(knots.rows() - u_deg - 1); + weights.setOnes(); + return weights; +} + + // DE BOOR ALGORITHM FROM OPENGLIDER std::function get_basis(int degree, int i, Eigen::VectorXd knots) // Return a basis_function for the given degree """ @@ -180,7 +203,7 @@ void add_triplets(Eigen::VectorXd values, double row, std::vector &triplet spMat NurbsBase2D::getInfluenceMatrix(Eigen::Matrix U) { std::vector triplets; - for (int row_index; row_index < U.rows(); row_index++) + for (unsigned int row_index = 0; row_index < U.rows(); row_index++) add_triplets(this->getInfluenceVector(U.row(row_index)), row_index, triplets); spMat mat(U.rows(), this->u_functions.size() * this->v_functions.size()); mat.setFromTriplets(triplets.begin(), triplets.end()); @@ -288,7 +311,7 @@ Eigen::VectorXd NurbsBase2D::getDvVector(Eigen::Vector2d u) spMat NurbsBase2D::getDuMatrix(Eigen::Matrix U) { std::vector triplets; - for (int row_index; row_index < U.rows(); row_index++) + for (unsigned int row_index = 0; row_index < U.rows(); row_index++) add_triplets(this->getDuVector(U.row(row_index)), row_index, triplets); spMat mat(U.rows(), this->u_functions.size() * this->v_functions.size()); mat.setFromTriplets(triplets.begin(), triplets.end()); @@ -298,13 +321,66 @@ spMat NurbsBase2D::getDuMatrix(Eigen::Matrix U) spMat NurbsBase2D::getDvMatrix(Eigen::Matrix U) { std::vector triplets; - for (int row_index; row_index < U.rows(); row_index++) + for (unsigned int row_index = 0; row_index < U.rows(); row_index++) add_triplets(this->getDvVector(U.row(row_index)), row_index, triplets); spMat mat(U.rows(), this->u_functions.size() * this->v_functions.size()); mat.setFromTriplets(triplets.begin(), triplets.end()); return mat; } + +std::tuple NurbsBase2D::interpolateUBS( + Eigen::Matrix poles, + int degree_u, + int degree_v, + int num_u_poles, + int num_v_poles, + int num_u_points, + int num_v_points) +{ + double u_min = this->u_knots(0); + double u_max = this->u_knots(this->u_knots.size() - 1); + double v_min = this->v_knots(0); + double v_max = this->v_knots(this->v_knots.size() - 1); + Eigen::VectorXd weights, u_knots, v_knots; + u_knots = NurbsBase1D::getKnotSequence(u_min, u_max, degree_u, num_u_poles); + v_knots = NurbsBase1D::getKnotSequence(v_min, v_max, degree_v, num_v_poles); + + weights.resize((u_knots.rows() - degree_u - 1) * (v_knots.rows() - degree_v - 1)); + weights.setOnes(); + NurbsBase2D new_base(u_knots, v_knots, weights, degree_u, degree_v); + Eigen::Matrix uv_points = this->getUVMesh(num_u_points, num_v_points); + Eigen::Matrix xyz_points = this->getInfluenceMatrix(uv_points) * poles; + spMat A = new_base.getInfluenceMatrix(uv_points); + Eigen::LeastSquaresConjugateGradient solver; + solver.compute(A); + Eigen::Matrix new_poles = solver.solve(xyz_points); + return std::tuple(new_base, new_poles); +} + +Eigen::Matrix NurbsBase2D::getUVMesh(int num_u_points, int num_v_points) +{ + double u_min = this->u_knots(0); + double u_max = this->u_knots(this->u_knots.size() - 1); + double v_min = this->v_knots(0); + double v_max = this->v_knots(this->v_knots.size() - 1); + Eigen::Matrix uv_points; + uv_points.resize(num_u_points * num_v_points, 2); + int i = 0; + for (int u = 0; u < num_u_points; u++) + { + for (int v = 0; v < num_v_points; v++) + { + uv_points(i, 0) = u_min + (u_max - u_min) * u / (num_u_points - 1); + uv_points(i, 1) = v_min + (v_max - v_min) * v / (num_v_points - 1); + i++; + } + + } + return uv_points; +} + + NurbsBase1D::NurbsBase1D(Eigen::VectorXd u_knots, Eigen::VectorXd weights, int degree_u) { this->u_knots = u_knots; @@ -336,7 +412,7 @@ Eigen::VectorXd NurbsBase1D::getInfluenceVector(double u) spMat NurbsBase1D::getInfluenceMatrix(Eigen::VectorXd u) { std::vector triplets; - for (int row_index; row_index < u.size(); row_index++) + for (unsigned int row_index = 0; row_index < u.size(); row_index++) add_triplets(this->getInfluenceVector(u[row_index]), row_index, triplets); spMat mat(u.size(), this->u_functions.size()); mat.setFromTriplets(triplets.begin(), triplets.end()); @@ -393,11 +469,44 @@ Eigen::VectorXd NurbsBase1D::getDuVector(double u) spMat NurbsBase1D::getDuMatrix(Eigen::VectorXd U) { std::vector triplets; - for (int row_index; row_index < U.size(); row_index++) + for (unsigned int row_index = 0; row_index < U.size(); row_index++) add_triplets(this->getDuVector(U[row_index]), row_index, triplets); spMat mat(U.size(), this->u_functions.size()); mat.setFromTriplets(triplets.begin(), triplets.end()); return mat; } +std::tuple> NurbsBase1D::interpolateUBS( + Eigen::Matrix poles, + int degree, + int num_poles, + int num_points) +{ + double u_min = this->u_knots(0); + double u_max = this->u_knots(this->u_knots.size() - 1); + Eigen::VectorXd u_knots, weights; + u_knots = NurbsBase1D::getKnotSequence(u_min, u_max, degree, num_poles); + weights = NurbsBase1D::getWeightList(u_knots, degree); + NurbsBase1D new_base(u_knots, weights, degree); + Eigen::Matrix u_points = this->getUMesh(num_points); + Eigen::Matrix xyz_points; + xyz_points = this->getInfluenceMatrix(u_points) * poles; + spMat A = new_base.getInfluenceMatrix(u_points); + Eigen::LeastSquaresConjugateGradient solver; + solver.compute(A); + Eigen::Matrix new_poles = solver.solve(xyz_points); + return std::tuple >(new_base, new_poles); +} + +Eigen::VectorXd NurbsBase1D::getUMesh(int num_u_points) +{ + double u_min = this->u_knots(0); + double u_max = this->u_knots(this->u_knots.size() - 1); + Eigen::Matrix u_points; + u_points.setLinSpaced(num_u_points, u_min, u_max); + return u_points; +} + + } diff --git a/src/Mod/MeshPart/App/MeshFlatteningNurbs.h b/src/Mod/MeshPart/App/MeshFlatteningNurbs.h index 073b17b5438f..2b5356f2f219 100644 --- a/src/Mod/MeshPart/App/MeshFlatteningNurbs.h +++ b/src/Mod/MeshPart/App/MeshFlatteningNurbs.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace nurbs{ @@ -67,13 +68,24 @@ struct NurbsBase2D Eigen::VectorXd getDvVector(Eigen::Vector2d u); spMat getDvMatrix(Eigen::Matrix U); + + Eigen::Matrix getUVMesh(int num_u_points, int num_v_points); + + std::tuple interpolateUBS( + Eigen::Matrix poles, + int degree_u, + int degree_v, + int num_u_poles, + int num_v_poles, + int num_u_points, + int num_v_points); }; struct NurbsBase1D { NurbsBase1D(){;}; NurbsBase1D(Eigen::VectorXd u_knots, Eigen::VectorXd weights, int degree_u=3); - int degree_u = degree_u; + int degree_u; Eigen::VectorXd u_knots; Eigen::VectorXd weights; std::vector> u_functions; @@ -88,6 +100,17 @@ struct NurbsBase1D Eigen::VectorXd getDuVector(double u); spMat getDuMatrix(Eigen::VectorXd u); + + static Eigen::VectorXd getKnotSequence(double u_min, double u_max, int deg, int num_poles); + static Eigen::VectorXd getWeightList(Eigen::VectorXd knots, int u_deg); + + Eigen::VectorXd getUMesh(int num_u_points); + + std::tuple> interpolateUBS( + Eigen::Matrix poles, + int degree, + int num_u_poles, + int num_u_points); }; diff --git a/src/Mod/MeshPart/App/MeshFlatteningPy.cpp b/src/Mod/MeshPart/App/MeshFlatteningPy.cpp index e255ea0c7285..f382c77274c0 100644 --- a/src/Mod/MeshPart/App/MeshFlatteningPy.cpp +++ b/src/Mod/MeshPart/App/MeshFlatteningPy.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #include +#include #include #include @@ -44,39 +45,62 @@ #include "MeshFlatteningNurbs.h" #include +#include #include +#include namespace py = pybind11; -// void FaceUnwrapper_constructor(FaceUnwrapper& instance, Part::TopoShapeFacePy Face) -FaceUnwrapper* FaceUnwrapper_constructor(py::object face) +const TopoDS_Face& getTopoDSFace(py::object* face) { - if (PyObject_TypeCheck(face.ptr(), &(Part::TopoShapeFacePy::Type))) + if (PyObject_TypeCheck(face->ptr(), &(Part::TopoShapeFacePy::Type))) { - const Part::TopoShapeFacePy* f = static_cast(face.ptr()); + const Part::TopoShapeFacePy* f = static_cast(face->ptr()); const TopoDS_Face& myFace = TopoDS::Face(f->getTopoShapePtr()->getShape()); - return new FaceUnwrapper(myFace); + return myFace; } else - throw std::invalid_argument("FaceUnwrapper should be initialized with Part.Face"); + throw std::invalid_argument("must be a face"); } -ColMat interpolateFlatFacePy(FaceUnwrapper& instance, py::object face) +const TopoDS_Edge& getTopoDSEdge(py::object* edge) { - std::cout << face.ptr()->ob_type->tp_name << std::endl; - std::cout << Part::TopoShapeFacePy::Type.tp_name << std::endl; - if (PyObject_TypeCheck(face.ptr(), &(Part::TopoShapeFacePy::Type))) + if (PyObject_TypeCheck(edge->ptr(), &(Part::TopoShapeEdgePy::Type))) { - const Part::TopoShapeFacePy* f = static_cast(face.ptr()); - const TopoDS_Face& myFace = TopoDS::Face(f->getTopoShapePtr()->getShape()); - return instance.interpolateFlatFace(myFace); + const Part::TopoShapeEdgePy* e = static_cast(edge->ptr()); + const TopoDS_Edge& myEdge = TopoDS::Edge(e->getTopoShapePtr()->getShape()); + return myEdge; } else - throw std::invalid_argument("FaceUnwrapper.interpolateNurbs should be initialized with Part.Face"); + throw std::invalid_argument("must be an edge"); +} + +Py::Object makeEdge(const TopoDS_Edge& edge) +{ + return Py::asObject(new Part::TopoShapeEdgePy(new Part::TopoShape(edge))); } +py::object makeFace(const TopoDS_Face& face) +{ + return py::cast(new Part::TopoShapeFacePy(new Part::TopoShape(face))); +} + + +FaceUnwrapper* FaceUnwrapper_constructor(py::object* face) +{ + const TopoDS_Face& myFace = getTopoDSFace(face); + return new FaceUnwrapper(myFace); +} + +ColMat interpolateFlatFacePy(FaceUnwrapper& instance, py::object* face) +{ + const TopoDS_Face& myFace = getTopoDSFace(face); + return instance.interpolateFlatFace(myFace); +} + + PYBIND11_MODULE(flatmesh, m) { m.doc() = "functions to unwrapp faces/ meshes"; @@ -96,21 +120,34 @@ PYBIND11_MODULE(flatmesh, m) py::class_(m, "NurbsBase2D") .def(py::init()) + .def_readonly("u_knots", &nurbs::NurbsBase2D::u_knots) + .def_readonly("weights", &nurbs::NurbsBase2D::weights) + .def_readonly("degree_u", &nurbs::NurbsBase2D::degree_u) + .def_readonly("v_knots", &nurbs::NurbsBase2D::u_knots) + .def_readonly("degree_v", &nurbs::NurbsBase2D::degree_u) + .def("getUVMesh", &nurbs::NurbsBase2D::getUVMesh) .def("computeFirstDerivatives", &nurbs::NurbsBase2D::computeFirstDerivatives) .def("getInfluenceVector", &nurbs::NurbsBase2D::getInfluenceVector) .def("getInfluenceMatrix", &nurbs::NurbsBase2D::getInfluenceMatrix) .def("getDuVector", &nurbs::NurbsBase2D::getDuVector) .def("getDuMatrix", &nurbs::NurbsBase2D::getDuMatrix) .def("getDvVector", &nurbs::NurbsBase2D::getDvVector) - .def("getDvMatrix", &nurbs::NurbsBase2D::getDvMatrix); + .def("getDvMatrix", &nurbs::NurbsBase2D::getDvMatrix) + .def("interpolateUBS", &nurbs::NurbsBase2D::interpolateUBS); py::class_(m, "NurbsBase1D") .def(py::init()) + .def_readonly("u_knots", &nurbs::NurbsBase1D::u_knots) + .def_readonly("weights", &nurbs::NurbsBase1D::weights) + .def_readonly("degree_u", &nurbs::NurbsBase1D::degree_u) + .def("getUMesh", &nurbs::NurbsBase1D::getUMesh) .def("computeFirstDerivatives", &nurbs::NurbsBase1D::computeFirstDerivatives) .def("getInfluenceVector", &nurbs::NurbsBase1D::getInfluenceVector) .def("getInfluenceMatrix", &nurbs::NurbsBase1D::getInfluenceMatrix) .def("getDuVector", &nurbs::NurbsBase1D::getDuVector) - .def("getDuMatrix", &nurbs::NurbsBase1D::getDuMatrix); + .def("getDuMatrix", &nurbs::NurbsBase1D::getDuMatrix) + .def_static("getKnotSequence", &nurbs::NurbsBase1D::getKnotSequence) + .def_static("getWeightList", &nurbs::NurbsBase1D::getWeightList); py::class_(m, "FaceUnwrapper") .def(py::init(&FaceUnwrapper_constructor)) @@ -124,4 +161,5 @@ PYBIND11_MODULE(flatmesh, m) .def_readonly("ze_nodes", &FaceUnwrapper::ze_nodes) .def_readonly("ze_poles", &FaceUnwrapper::ze_poles) .def_readonly("A", &FaceUnwrapper::A); + }; diff --git a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py index 1b0229f3aade..9678ee1635dd 100644 --- a/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py +++ b/src/Mod/MeshPart/Gui/MeshFlatteningCommand.py @@ -1,7 +1,10 @@ -import FreeCADGui as gui import Mesh import FreeCAD as App -import FreeCADGui as gui +import FreeCADGui as Gui +import Part +import numpy as np +from pivy import graphics as g +from pivy import coin class BaseCommand(object): def __init__(self): @@ -12,6 +15,7 @@ def IsActive(self): return False else: return True + class CreateFlatMesh(BaseCommand): """create flat wires from a meshed face""" @@ -22,15 +26,14 @@ def GetResources(self): def Activated(self): import numpy as np import flatmesh - import Part - obj = gui.Selection.getSelection()[0] # obj must be a Mesh (Mesh-Design->Meshes->Create-Mesh) - mesh = Mesh.Mesh(obj.Mesh) # copy of the mesh to set new vertices later on + obj = Gui.Selection.getSelection()[0] # obj must be a Mesh (Mesh-Design->Meshes->Create-Mesh) points = np.array([[i.x, i.y, i.z] for i in obj.Mesh.Points]) faces = np.array([list(i) for i in obj.Mesh.Topology[1]]) - print(faces) flattener = flatmesh.FaceUnwrapper(points, faces) - flattener.findFlatNodes() + flattener.findFlatNodes(5, 0.99) boundaries = flattener.getFlatBoundaryNodes() + print(flattener.ze_nodes) + print(boundaries) wires = [] for edge in boundaries: pi = Part.makePolygon([App.Vector(*node) for node in edge]) @@ -38,9 +41,10 @@ def Activated(self): def IsActive(self): assert(super(CreateFlatMesh, self).IsActive()) - assert(isinstance(gui.Selection.getSelection()[0].Mesh, Mesh.Mesh)) + assert(isinstance(Gui.Selection.getSelection()[0].Mesh, Mesh.Mesh)) return True + class CreateFlatFace(BaseCommand): """create a flat face from a single face only full faces are supported right now""" @@ -48,11 +52,34 @@ class CreateFlatFace(BaseCommand): def GetResources(self): return {'MenuText': 'Unwrap Face', 'ToolTip': 'find a flat representation of a mesh'} + def Activated(self): + import numpy as np + import flatmesh + face = Gui.Selection.getSelectionEx()[0].SubObjects[0] + shape = face.toNurbs() + face = shape.Faces[0] + nurbs = face.Surface + nurbs.setUNotPeriodic() + nurbs.setVNotPeriodic() + bs = nurbs.toBSpline(1, "C0", "C0", 3, 3, 10) + face = bs.toShape() + face.tessellate(0.01) + flattener = flatmesh.FaceUnwrapper(face) + flattener.findFlatNodes(5, 0.99) + poles = flattener.interpolateFlatFace(face) + num_u_poles = len(bs.getPoles()) + num_v_poles = len(bs.getPoles()[0]) + i = 0 + for u in range(num_u_poles): + for v in range(num_v_poles): + bs.setPole(u + 1, v + 1, App.Vector(poles[i])) + i += 1 + Part.show(bs.toShape()) + def IsActive(self): - assert(super(CreateFlatMesh, self).IsActive()) - assert(isinstance(gui.Selection.getSelection()[0], Part.Face)) + assert(super(CreateFlatFace, self).IsActive()) + assert(isinstance(Gui.Selection.getSelectionEx()[0].SubObjects[0], Part.Face)) return True - - -gui.addCommand('CreateFlatMesh', CreateFlatMesh()) +Gui.addCommand('CreateFlatMesh', CreateFlatMesh()) +Gui.addCommand('CreateFlatFace', CreateFlatFace())