MeshFlattener: boundary extractor

This commit is contained in:
looooo
2017-09-18 22:00:06 +02:00
committed by wmayer
parent ce33e2dbe2
commit e1247dcb48
8 changed files with 204 additions and 18 deletions

View File

@@ -29,7 +29,6 @@
#* Werner Mayer 2004 *
#***************************************************************************/
class MeshWorkbench (Workbench):
"Mesh workbench object"
def __init__(self):
@@ -40,6 +39,13 @@ class MeshWorkbench (Workbench):
def Initialize(self):
import Mesh
import MeshGui
# try:
import MeshFlatteningCommand
toolbar = MeshFlatteningCommand.initialize()
self.appendToolbar(toolbar)
# except ImportError:
# import FreeCAD as app
# app.Message("MeshPart not found")
def GetClassName(self):
return "MeshGui::Workbench"

View File

@@ -80,6 +80,9 @@ SET_PYTHON_PREFIX_SUFFIX(MeshPart)
INSTALL(TARGETS MeshPart DESTINATION ${CMAKE_INSTALL_LIBDIR})
################################ flat mesh ###############################
SET(FLATMESH_SRCS
MeshFlatteningPy.cpp
MeshFlattening.cpp
@@ -91,9 +94,11 @@ SET(FLATMESH_SRCS
)
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})
############################################################################

View File

@@ -28,9 +28,104 @@
#include <Geom_Surface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <set>
#include <map>
#include <vector>
#include <exception>
std::vector<ColMat<double, 3>> getBoundaries(ColMat<double, 3> vertices, ColMat<long, 3> tris)
{
// get a hashtable for all edges
// e: v1, v2, num
std::map<std::set<long>, std::vector<long>> hash_map;
std::vector<std::set<long>> hash_list;
std::map<long, std::vector<long>> neighbour_map;
std::vector<long> edge_vector_0;
std::vector<std::vector<long>> edge_vector;
for (long i=0; i<tris.rows(); i++)
{
for (long j=0; j<3; j++)
{
long k = j + 1;
if (k == 3)
k = 0;
long v1 = tris(i, j);
long v2 = tris(i, k);
std::set<long> hash {v1, v2};
hash_list.push_back(hash);
if (v1 < v2)
hash_map[hash] = std::vector<long>{v1, v2, 0};
else
hash_map[hash] = std::vector<long>{v2, v1, 0};
}
}
for (auto & hash: hash_list)
hash_map[hash][2] += 1;
for (auto &hash: hash_map)
{
if (hash.second[2] == 1)
{
long v0 = hash.second[0];
long v1 = hash.second[1];
neighbour_map[v0].push_back(v1);
neighbour_map[v1].push_back(v0);
}
}
while (neighbour_map.size() != 0)
{
long start_index = neighbour_map.begin()->first;
long close_index = start_index;
long next_index = neighbour_map[start_index][1];
long temporary_next;
edge_vector_0.clear();
edge_vector_0.push_back(close_index);
edge_vector_0.push_back(start_index);
neighbour_map.erase(start_index);
edge_vector_0.push_back(next_index);
while (next_index != close_index)
{
temporary_next = neighbour_map[next_index][0];
if (temporary_next != start_index)
{
start_index = next_index;
next_index = temporary_next;
}
else
{
start_index = next_index;
next_index = neighbour_map[start_index][1];
}
neighbour_map.erase(start_index);
edge_vector_0.push_back(next_index);
}
edge_vector.push_back(edge_vector_0);
}
std::vector<ColMat<double, 3>> edges;
for (auto &edge: edge_vector)
{
ColMat<double, 3> edge_vertices;
edge_vertices.resize(edge.size(), 3);
int i = 0;
for (auto index: edge)
{
edge_vertices.row(i) = vertices.row(index);
i++;
}
edges.push_back(edge_vertices);
}
return edges;
}
FaceUnwrapper::FaceUnwrapper(const TopoDS_Face& face)
{
int i = 0;
long i = 0;
// transform to nurbs:
TopLoc_Location location;
@@ -76,15 +171,18 @@ FaceUnwrapper::FaceUnwrapper(const TopoDS_Face& face)
void FaceUnwrapper::findFlatNodes()
{
std::vector<long> fixed_pins;
std::vector<long> fixed_pins; //TODO: INPUT
LscmRelax mesh_flattener(this->xyz_nodes.transpose(), this->tris.transpose(), fixed_pins);
mesh_flattener.lscm();
mesh_flattener.relax(0.9);
this->ze_nodes = mesh_flattener.flat_vertices.transpose();
}
ColMat<double, 3> FaceUnwrapper::interpolateNurbsFace(const TopoDS_Face& face)
ColMat<double, 3> FaceUnwrapper::interpolateFlatFace(const TopoDS_Face& face)
{
if (this->uv_nodes.size() == 0)
throw(std::runtime_error("no uv-coordinates found, interpolating with nurbs is only possible if the Flattener was constructed with a nurbs."));
// extract xyz poles, knots, weights, degree
const Handle(Geom_Surface) &_surface = BRep_Tool::Surface(face);
const Handle(Geom_BSplineSurface) &_bspline = Handle(Geom_BSplineSurface)::DownCast(_surface);
@@ -93,10 +191,10 @@ ColMat<double, 3> FaceUnwrapper::interpolateNurbsFace(const TopoDS_Face& face)
Eigen::VectorXd weights;
weights.resize(_bspline->NbUPoles() * _bspline->NbVPoles());
int i = 0;
for (int u=1; u <= _bspline->NbUPoles(); u++)
long i = 0;
for (long u=1; u <= _bspline->NbUPoles(); u++)
{
for (int v=1; v <= _bspline->NbVPoles(); v++)
for (long v=1; v <= _bspline->NbVPoles(); v++)
{
weights[i] = _bspline->Weight(u, v);
i++;
@@ -107,11 +205,11 @@ ColMat<double, 3> FaceUnwrapper::interpolateNurbsFace(const TopoDS_Face& face)
Eigen::VectorXd v_knots;
u_knots.resize(_uknots.Size());
v_knots.resize(_vknots.Size());
for (int u=1; u <= _uknots.Size(); u++)
for (long u=1; u <= _uknots.Size(); u++)
{
u_knots[u - 1] = _uknots.Value(u);
}
for (int v=1; v <= _vknots.Size(); v++)
for (long v=1; v <= _vknots.Size(); v++)
{
v_knots[v - 1] = _vknots.Value(v);
}
@@ -134,9 +232,22 @@ ColMat<double, 3> FaceUnwrapper::interpolateNurbsFace(const TopoDS_Face& face)
}
FaceUnwrapper::FaceUnwrapper(ColMat< double, int(3) > xyz_nodes, ColMat< long int, int(3) > tris)
{
this->tris = tris;
this->xyz_nodes = xyz_nodes;
}
std::vector<ColMat<double, 3>> FaceUnwrapper::getFlatBoundaryNodes()
{
if (this->ze_nodes.size() == 0)
throw(std::runtime_error("flat vertices not xet computed"));
ColMat<double, 3> flat_vertices;
flat_vertices.resize(this->ze_nodes.rows(), 3);
flat_vertices.setZero();
flat_vertices.col(0) << this->ze_nodes.col(0);
flat_vertices.col(1) << this->ze_nodes.col(1);
return getBoundaries(flat_vertices, this->tris);
}

View File

@@ -20,6 +20,11 @@
* *
***************************************************************************/
// idea:
// - unwrap any meshed shells and output a 2d face (meshing is done externally)
// - unwrap faces which are nurbs and return nurbs (no cuts, meshing internally)
#ifndef MESHFLATTENING
#define MESHFLATTENING
@@ -33,6 +38,8 @@
#include <Eigen/SparseCore>
#include <Eigen/QR>
#include <vector>
typedef Eigen::Vector3d Vector3;
typedef Eigen::Vector2d Vector2;
@@ -47,12 +54,17 @@ using RowMat = Eigen::Matrix<type, size, Eigen::Dynamic>;
typedef Eigen::Triplet<double> trip;
typedef Eigen::SparseMatrix<double> spMat;
std::vector<ColMat<double, 3>> getBoundaries(ColMat<double, 3> vertices, ColMat<long, 3> tris);
class FaceUnwrapper{
nurbs::NurbsBase2D nu;
public:
FaceUnwrapper(const TopoDS_Face & face);
FaceUnwrapper(ColMat<double, 3> xyz_nodes, ColMat<long, 3> tris);
void findFlatNodes();
ColMat<double, 3> interpolateNurbsFace(const TopoDS_Face& face);
ColMat<double, 3> interpolateFlatFace(const TopoDS_Face& face);
std::vector<ColMat<double, 3>> getFlatBoundaryNodes();
bool use_nurbs = true;
// the mesh

View File

@@ -63,7 +63,7 @@ FaceUnwrapper* FaceUnwrapper_constructor(py::object face)
throw std::invalid_argument("FaceUnwrapper should be initialized with Part.Face");
}
ColMat<double, 3> interpolateNurbsFacePy(FaceUnwrapper& instance, py::object face)
ColMat<double, 3> interpolateFlatFacePy(FaceUnwrapper& instance, py::object face)
{
std::cout << face.ptr()->ob_type->tp_name << std::endl;
std::cout << Part::TopoShapeFacePy::Type.tp_name << std::endl;
@@ -71,7 +71,7 @@ ColMat<double, 3> interpolateNurbsFacePy(FaceUnwrapper& instance, py::object fac
{
const Part::TopoShapeFacePy* f = static_cast<Part::TopoShapeFacePy*>(face.ptr());
const TopoDS_Face& myFace = TopoDS::Face(f->getTopoShapePtr()->getShape());
return instance.interpolateNurbsFace(myFace);
return instance.interpolateFlatFace(myFace);
}
else
throw std::invalid_argument("FaceUnwrapper.interpolateNurbs should be initialized with Part.Face");
@@ -114,8 +114,10 @@ PYBIND11_MODULE(flatmesh, m)
py::class_<FaceUnwrapper>(m, "FaceUnwrapper")
.def(py::init(&FaceUnwrapper_constructor))
.def(py::init<ColMat<double, 3>, ColMat<long, 3>>())
.def("findFlatNodes", &FaceUnwrapper::findFlatNodes)
.def("interpolateNurbsFace", &interpolateNurbsFacePy)
.def("interpolateFlatFace", &interpolateFlatFacePy)
.def("getFlatBoundaryNodes", &FaceUnwrapper::getFlatBoundaryNodes)
.def_readonly("tris", &FaceUnwrapper::tris)
.def_readonly("nodes", &FaceUnwrapper::xyz_nodes)
.def_readonly("uv_nodes", &FaceUnwrapper::uv_nodes)

View File

@@ -86,3 +86,12 @@ SET_BIN_DIR(MeshPartGui MeshPartGui /Mod/MeshPart)
SET_PYTHON_PREFIX_SUFFIX(MeshPartGui)
INSTALL(TARGETS MeshPartGui DESTINATION ${CMAKE_INSTALL_LIBDIR})
SET(FLATMESH_PY_SRCS
MeshFlatteningCommand.py
)
fc_copy_sources(MeshPartGui "${CMAKE_BINARY_DIR}/Mod/MeshPart" ${FLATMESH_PY_SRCS})
INSTALL(FILES ${FLATMESH_PY_SRCS} DESTINATION Mod/MeshPart)

View File

@@ -0,0 +1,42 @@
import numpy as np
import Mesh
import FreeCAD as app
import flatMesh
import Part
class BaseCommand(object):
def __init__(self):
pass
def IsActive(self):
if FreeCAD.ActiveDocument is None:
return False
else:
return True
class CreateFlatMesh(BaseCommand):
"""create an involute gear"""
def GetResources(self):
return {'Pixmap': 'not_yet.svg', 'MenuText': 'unwrap mesh', 'ToolTip': 'find a flat representation of a mesh'}
def Activated(self):
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
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]])
flattener = flatMesh.FaceUnwrapper(points, faces)
flattener.findFlatNodes()
boundaries = flattener.getFlatBoundaryNodes()
wires = []
for edge in boundaries:
pi = Part.makePolygon([app.Vector(*node) for node in edge])
wires.append(pi)
Part.show(Part.Wire(wires))
def initialize():
Gui.addCommand('CreateFlatMesh', CreateFlatMesh())
return ["CreateFlatMesh"]

View File

@@ -30,7 +30,6 @@
#***************************************************************************/
class MeshPartWorkbench ( Workbench ):
"MeshPart workbench object"
Icon = """