MeshFlattening: add function to unwrap face

This commit is contained in:
looooo
2017-10-11 23:38:12 +02:00
committed by wmayer
parent 2329ac38e8
commit 76b66159b3
12 changed files with 279 additions and 63 deletions

View File

@@ -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 --------------------------------

View File

@@ -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;
}

View File

@@ -39,8 +39,12 @@ class MeshWorkbench (Workbench):
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"

View File

@@ -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()

View File

@@ -169,13 +169,13 @@ FaceUnwrapper::FaceUnwrapper(const TopoDS_Face& face)
}
}
void FaceUnwrapper::findFlatNodes()
void FaceUnwrapper::findFlatNodes(int steps, double val)
{
std::vector<long> 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; j<steps; j++)
mesh_flattener.relax(0.95);
this->ze_nodes = mesh_flattener.flat_vertices.transpose();
}

View File

@@ -62,7 +62,7 @@ class FaceUnwrapper{
public:
FaceUnwrapper(const TopoDS_Face & face);
FaceUnwrapper(ColMat<double, 3> xyz_nodes, ColMat<long, 3> tris);
void findFlatNodes();
void findFlatNodes(int steps, double val);
ColMat<double, 3> interpolateFlatFace(const TopoDS_Face& face);
std::vector<ColMat<double, 3>> getFlatBoundaryNodes();

View File

@@ -23,6 +23,7 @@
#include "MeshFlatteningLscmRelax.h"
#include <Eigen/IterativeLinearSolvers>
#include<Eigen/SparseCholesky>
#include <Eigen/SVD>
#include <iostream>
#include <algorithm>
@@ -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<spMat, Eigen::Lower> solver;
solver.setTolerance(0.0000001);
Eigen::SimplicialLDLT<spMat, Eigen::Lower> 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();
}

View File

@@ -88,7 +88,7 @@ public:
ColMat<double, 1> rhs;
Eigen::MatrixXd MATRIX;
double nue=0.0;
double nue=0.9;
double elasticity=1.;
void lscm();

View File

@@ -25,6 +25,7 @@
#include <iostream>
#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<double> 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<Eigen::VectorXd>(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<double(double)> 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<trip> &triplet
spMat NurbsBase2D::getInfluenceMatrix(Eigen::Matrix<double, Eigen::Dynamic, 2> U)
{
std::vector<trip> 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<double, Eigen::Dynamic, 2> U)
{
std::vector<trip> 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<double, Eigen::Dynamic, 2> U)
spMat NurbsBase2D::getDvMatrix(Eigen::Matrix<double, Eigen::Dynamic, 2> U)
{
std::vector<trip> 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, Eigen::MatrixXd> NurbsBase2D::interpolateUBS(
Eigen::Matrix<double, Eigen::Dynamic, 3> 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<double, Eigen::Dynamic, 2> uv_points = this->getUVMesh(num_u_points, num_v_points);
Eigen::Matrix<double, Eigen::Dynamic, 3> xyz_points = this->getInfluenceMatrix(uv_points) * poles;
spMat A = new_base.getInfluenceMatrix(uv_points);
Eigen::LeastSquaresConjugateGradient<spMat > solver;
solver.compute(A);
Eigen::Matrix<double, Eigen::Dynamic, 3> new_poles = solver.solve(xyz_points);
return std::tuple<NurbsBase2D, Eigen::MatrixXd >(new_base, new_poles);
}
Eigen::Matrix<double, Eigen::Dynamic, 2> 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<double, Eigen::Dynamic, 2> 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<trip> 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<trip> 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, Eigen::Matrix<double, Eigen::Dynamic, 3>> NurbsBase1D::interpolateUBS(
Eigen::Matrix<double,
Eigen::Dynamic, 3> 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<double, Eigen::Dynamic, 1> u_points = this->getUMesh(num_points);
Eigen::Matrix<double, Eigen::Dynamic, 3> xyz_points;
xyz_points = this->getInfluenceMatrix(u_points) * poles;
spMat A = new_base.getInfluenceMatrix(u_points);
Eigen::LeastSquaresConjugateGradient<spMat > solver;
solver.compute(A);
Eigen::Matrix<double, Eigen::Dynamic, 3> new_poles = solver.solve(xyz_points);
return std::tuple<NurbsBase1D, Eigen::Matrix<double, Eigen::Dynamic, 3> >(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<double, Eigen::Dynamic, 1> u_points;
u_points.setLinSpaced(num_u_points, u_min, u_max);
return u_points;
}
}

View File

@@ -28,6 +28,7 @@
#include <Eigen/Geometry>
#include <Eigen/IterativeLinearSolvers>
#include <Eigen/SparseCore>
#include <tuple>
namespace nurbs{
@@ -67,13 +68,24 @@ struct NurbsBase2D
Eigen::VectorXd getDvVector(Eigen::Vector2d u);
spMat getDvMatrix(Eigen::Matrix<double, Eigen::Dynamic, 2> U);
Eigen::Matrix<double, Eigen::Dynamic, 2> getUVMesh(int num_u_points, int num_v_points);
std::tuple<NurbsBase2D, Eigen::MatrixXd> interpolateUBS(
Eigen::Matrix<double, Eigen::Dynamic, 3> 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<std::function<double(double)>> 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<NurbsBase1D, Eigen::Matrix<double, Eigen::Dynamic, 3>> interpolateUBS(
Eigen::Matrix<double, Eigen::Dynamic, 3> poles,
int degree,
int num_u_poles,
int num_u_points);
};

View File

@@ -23,6 +23,7 @@
#include "PreCompiled.h"
#include <Mod/Part/App/TopoShapeFacePy.h>
#include <Mod/Part/App/TopoShapeEdgePy.h>
#include <Eigen/Core>
#include <Eigen/Geometry>
@@ -44,39 +45,62 @@
#include "MeshFlatteningNurbs.h"
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS.hxx>
#include <ShapeFix_Edge.hxx>
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<Part::TopoShapeFacePy*>(face.ptr());
const Part::TopoShapeFacePy* f = static_cast<Part::TopoShapeFacePy*>(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<double, 3> 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<Part::TopoShapeFacePy*>(face.ptr());
const TopoDS_Face& myFace = TopoDS::Face(f->getTopoShapePtr()->getShape());
return instance.interpolateFlatFace(myFace);
const Part::TopoShapeEdgePy* e = static_cast<Part::TopoShapeEdgePy*>(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<double, 3> 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_<nurbs::NurbsBase2D>(m, "NurbsBase2D")
.def(py::init<Eigen::VectorXd, Eigen::VectorXd, Eigen::VectorXd, int, int>())
.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_<nurbs::NurbsBase1D>(m, "NurbsBase1D")
.def(py::init<Eigen::VectorXd, Eigen::VectorXd, int>())
.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_<FaceUnwrapper>(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);
};

View File

@@ -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 @@ class BaseCommand(object):
return False
else:
return True
class CreateFlatMesh(BaseCommand):
"""create flat wires from a meshed face"""
@@ -22,15 +26,14 @@ class CreateFlatMesh(BaseCommand):
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 @@ class CreateFlatMesh(BaseCommand):
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())