gmio_support: fix duplicated vertices when reading STL file into StlMesh_Mesh

This commit is contained in:
Hugues Delorme 2016-06-29 16:52:32 +02:00
parent 25d2ff32fb
commit d2ba019733
15 changed files with 276 additions and 106 deletions

View File

@ -92,7 +92,10 @@ find_library(
DOC "Path to the TKMesh import library")
find_library(
LIB_OPENCASCADE_TKSTEP TKSTEP ${LIBDIR_OPENCASCADE}
DOC "Path to the TKMesh import library")
DOC "Path to the TKSTEP import library")
find_library(
LIB_OPENCASCADE_TKTOPALGO TKTopAlgo ${LIBDIR_OPENCASCADE}
DOC "Path to the TKTopAlgo import library")
target_link_libraries(
benchmark_opencascade
@ -103,4 +106,5 @@ target_link_libraries(
${LIB_OPENCASCADE_TKIGES}
${LIB_OPENCASCADE_TKBREP}
${LIB_OPENCASCADE_TKMESH}
${LIB_OPENCASCADE_TKSTEP})
${LIB_OPENCASCADE_TKSTEP}
${LIB_OPENCASCADE_TKTOPALGO})

View File

@ -169,7 +169,7 @@ Handle_StlMesh_Mesh stlMesh;
static void stl_read(const void* filepath)
{
stlMesh = new StlMesh_Mesh;
gmio_stl_mesh_creator mesh_creator = gmio_stl_occmesh_creator(stlMesh);
gmio_stl_mesh_creator_occmesh mesh_creator(stlMesh);
const int error = gmio_stl_read_file(
static_cast<const char*>(filepath), &mesh_creator, NULL);
if (error != GMIO_ERROR_OK)

View File

@ -25,7 +25,7 @@ int main(int argc, char** argv)
if (argc > 1) {
const char* filepath = argv[1];
Handle_StlMesh_Mesh mesh = new StlMesh_Mesh;
gmio_stl_mesh_creator mesh_creator = gmio_stl_occmesh_creator(mesh);
gmio_stl_mesh_creator_occmesh mesh_creator(mesh);
// Read, using default options(NULL)
error = gmio_stl_read_file(filepath, &mesh_creator, NULL);

View File

@ -15,7 +15,7 @@ void my_mesh_creator__begin_solid(
void* cookie, const gmio_stl_mesh_creator_infos* infos)
{
gmio_stl_mesh_creator* base_creator =
reinterpret_cast<gmio_stl_mesh_creator*>(cookie);
static_cast<gmio_stl_mesh_creator*>(cookie);
base_creator->func_begin_solid(base_creator->cookie, infos);
// Do something more ...
}
@ -25,7 +25,7 @@ void my_mesh_creator__add_triangle(
void* cookie, uint32_t tri_id, const gmio_stl_triangle* triangle)
{
gmio_stl_mesh_creator* base_creator =
reinterpret_cast<gmio_stl_mesh_creator*>(cookie);
static_cast<gmio_stl_mesh_creator*>(cookie);
base_creator->func_add_triangle(base_creator->cookie, tri_id, triangle);
// Do something more ...
}
@ -36,7 +36,7 @@ int main(int argc, char** argv)
if (argc > 1) {
const char* filepath = argv[1];
Handle_StlMesh_Mesh mesh = new StlMesh_Mesh;
gmio_stl_mesh_creator base_creator = gmio_stl_occmesh_creator(mesh);
gmio_stl_mesh_creator_occmesh base_creator(mesh);
gmio_stl_mesh_creator creator = {};
creator.cookie = &base_creator;
creator.func_begin_solid = my_mesh_creator__begin_solid;

View File

@ -18,49 +18,19 @@
#include "stl_occ_utils.h"
#include <cstring>
#include <gp_Pnt.hxx>
#include <Precision.hxx>
#include <StlMesh_Mesh.hxx>
#include <StlMesh_MeshTriangle.hxx>
#include <StlMesh_SequenceOfMeshTriangle.hxx>
#include <TColgp_SequenceOfXYZ.hxx>
namespace internal {
static void occmesh_add_triangle(
void* cookie, uint32_t tri_id, const gmio_stl_triangle* tri)
{
StlMesh_Mesh* mesh = static_cast<StlMesh_Mesh*>(cookie);
if (tri_id == 0)
mesh->AddDomain();
const gmio_vec3f& v1 = tri->v1;
const gmio_vec3f& v2 = tri->v2;
const gmio_vec3f& v3 = tri->v3;
const gmio_vec3f& n = tri->n;
mesh->AddTriangle(mesh->AddOnlyNewVertex(v1.x, v1.y, v1.z),
mesh->AddOnlyNewVertex(v2.x, v2.y, v2.z),
mesh->AddOnlyNewVertex(v3.x, v3.y, v3.z),
n.x, n.y, n.z);
}
} // namespace internal
gmio_stl_mesh_creator gmio_stl_occmesh_creator(StlMesh_Mesh* mesh)
{
gmio_stl_mesh_creator creator = {};
creator.cookie = mesh;
creator.func_add_triangle = internal::occmesh_add_triangle;
return creator;
}
gmio_stl_mesh_creator gmio_stl_occmesh_creator(const Handle_StlMesh_Mesh &hnd)
{
return gmio_stl_occmesh_creator(hnd.operator->());
}
// -----------------------------------------------------------------------------
// gmio_stl_mesh_occmesh
// -----------------------------------------------------------------------------
gmio_stl_mesh_occmesh::gmio_stl_mesh_occmesh()
: m_mesh(NULL),
m_mesh_domain_count(0),
m_seq_triangle(NULL),
m_seq_vertex(NULL)
: m_mesh(NULL)
{
this->init_C_members();
}
@ -91,58 +61,131 @@ void gmio_stl_mesh_occmesh::get_triangle(
{
const gmio_stl_mesh_occmesh* it =
static_cast<const gmio_stl_mesh_occmesh*>(cookie);
const StlMesh_MeshTriangle* occ_tri;
const TColgp_SequenceOfXYZ* occ_vertices;
if (it->m_mesh_domain_count > 1) {
const triangle_data& tridata = it->m_vec_triangle_data.at(tri_id);
occ_tri = tridata.ptr_triangle;
occ_vertices = tridata.ptr_vec_vertices;
}
else {
occ_tri = it->m_seq_triangle->Value(tri_id + 1).operator->();
occ_vertices = it->m_seq_vertex;
}
const std::vector<const gp_XYZ*>& vec_coords = tridata.ptr_domain->vec_coords;
int iv1, iv2, iv3;
double nx, ny, nz;
occ_tri->GetVertexAndOrientation(iv1, iv2, iv3, nx, ny, nz);
tridata.ptr_triangle->GetVertexAndOrientation(iv1, iv2, iv3, nx, ny, nz);
gmio_stl_occ_copy_xyz(&tri->n, nx, ny, nz);
gmio_stl_occ_copy_xyz(&tri->v1, occ_vertices->Value(iv1));
gmio_stl_occ_copy_xyz(&tri->v2, occ_vertices->Value(iv2));
gmio_stl_occ_copy_xyz(&tri->v3, occ_vertices->Value(iv3));
gmio_stl_occ_copy_xyz(&tri->v1, *vec_coords.at(iv1 - 1));
gmio_stl_occ_copy_xyz(&tri->v2, *vec_coords.at(iv2 - 1));
gmio_stl_occ_copy_xyz(&tri->v3, *vec_coords.at(iv3 - 1));
}
void gmio_stl_mesh_occmesh::init_cache()
{
if (m_mesh == NULL)
return;
// Count triangles
m_mesh_domain_count = m_mesh != NULL ? m_mesh->NbDomains() : 0;
for (int dom_id = 1; dom_id <= m_mesh_domain_count; ++dom_id)
const int domain_count = m_mesh != NULL ? m_mesh->NbDomains() : 0;
for (int dom_id = 1; dom_id <= domain_count; ++dom_id)
this->triangle_count += m_mesh->NbTriangles(dom_id);
if (m_mesh_domain_count > 1) {
// Fill vector of triangle data
m_vec_triangle_data.reserve(this->triangle_count);
for (int dom_id = 1; dom_id <= m_mesh_domain_count; ++dom_id) {
for (int dom_id = 1; dom_id <= domain_count; ++dom_id) {
// Cache vertex indexes
// TColgp_SequenceOfXYZ::Value(int) is slow(linear search)
const TColgp_SequenceOfXYZ& seq_vertices = m_mesh->Vertices(dom_id);
struct domain_data domdata;
domdata.vec_coords.reserve(seq_vertices.Size());
typedef TColgp_SequenceOfXYZ::const_iterator ConstIterSeqXYZ;
const ConstIterSeqXYZ seq_end = seq_vertices.cend();
for (ConstIterSeqXYZ it = seq_vertices.cbegin(); it != seq_end; ++it)
domdata.vec_coords.push_back(&(*it));
m_vec_domain_data.push_back(std::move(domdata));
// Cache triangles
const StlMesh_SequenceOfMeshTriangle& seq_triangles =
m_mesh->Triangles(dom_id);
const TColgp_SequenceOfXYZ& seq_vertices =
m_mesh->Vertices(dom_id);
for (int tri_id = 1; tri_id <= seq_triangles.Length(); ++tri_id) {
const Handle_StlMesh_MeshTriangle& hnd_occtri =
seq_triangles.Value(tri_id);
struct triangle_data tridata;
tridata.ptr_triangle = hnd_occtri.operator->();
tridata.ptr_vec_vertices = &seq_vertices;
tridata.ptr_domain = &m_vec_domain_data.back();
m_vec_triangle_data.push_back(std::move(tridata));
}
}
}
else {
m_seq_triangle = &m_mesh->Triangles(1);
m_seq_vertex = &m_mesh->Vertices(1);
}
}
// -----------------------------------------------------------------------------
// gmio_stl_mesh_creator_occmesh
// -----------------------------------------------------------------------------
gmio_stl_mesh_creator_occmesh::gmio_stl_mesh_creator_occmesh()
: m_mesh(NULL),
m_filter(Precision::Confusion()),
m_inspector(Precision::Confusion())
{
this->init_C_members();
}
gmio_stl_mesh_creator_occmesh::gmio_stl_mesh_creator_occmesh(StlMesh_Mesh *mesh)
: m_mesh(mesh),
m_filter(Precision::Confusion()),
m_inspector(Precision::Confusion())
{
this->init_C_members();
}
gmio_stl_mesh_creator_occmesh::gmio_stl_mesh_creator_occmesh(
const Handle_StlMesh_Mesh &hnd)
: m_mesh(hnd.operator->()),
m_filter(Precision::Confusion()),
m_inspector(Precision::Confusion())
{
this->init_C_members();
}
void gmio_stl_mesh_creator_occmesh::begin_solid(
void* cookie, const gmio_stl_mesh_creator_infos* /*infos*/)
{
gmio_stl_mesh_creator_occmesh* creator =
static_cast<gmio_stl_mesh_creator_occmesh*>(cookie);
creator->m_mesh->AddDomain();
}
void gmio_stl_mesh_creator_occmesh::add_triangle(
void *cookie, uint32_t /*tri_id*/, const gmio_stl_triangle *tri)
{
gmio_stl_mesh_creator_occmesh* creator =
static_cast<gmio_stl_mesh_creator_occmesh*>(cookie);
const gmio_vec3f& n = tri->n;
creator->m_mesh->AddTriangle(
creator->add_unique_vertex(tri->v1),
creator->add_unique_vertex(tri->v2),
creator->add_unique_vertex(tri->v3),
n.x, n.y, n.z);
}
void gmio_stl_mesh_creator_occmesh::init_C_members()
{
this->cookie = this;
this->func_begin_solid = &gmio_stl_mesh_creator_occmesh::begin_solid;
this->func_add_triangle = &gmio_stl_mesh_creator_occmesh::add_triangle;
this->func_end_solid = NULL;
}
int gmio_stl_mesh_creator_occmesh::add_unique_vertex(const gmio_vec3f& v)
{
//--------------------------------------------------------------------------
// Code excerpted from OpenCascade v7.0.0
// File: RWStl/RWStl.cxx
// Function: "static int AddVertex(...)" lines 38..61
//--------------------------------------------------------------------------
const gp_XYZ pnt(v.x, v.y, v.z);
m_inspector.SetCurrent(pnt);
const gp_XYZ min_pnt = m_inspector.Shift(pnt, -Precision::Confusion());
const gp_XYZ max_pnt = m_inspector.Shift(pnt, +Precision::Confusion());
m_filter.Inspect(min_pnt, max_pnt, m_inspector);
if (!m_inspector.ResInd().IsEmpty()) {
const int index = m_inspector.ResInd().First(); // There should be only one
m_inspector.ClearResList();
return index;
}
const int index = m_mesh->AddVertex(pnt.X(), pnt.Y(), pnt.Z());
m_filter.Add(index, pnt);
m_inspector.Add(pnt);
return index;
}

View File

@ -23,7 +23,7 @@
*
* Of course this requires the includepath and libpath to point to OpenCascade,
* the import libraries likely needed are:\n
* <tt>TKernel TKMath TKSTL</tt>
* <tt>TKernel TKMath TKSTL TKTopAlgo</tt>
*
* \addtogroup gmio_support
* @{
@ -42,6 +42,8 @@
#include <vector>
#include <BRepBuilderAPI_CellFilter.hxx>
#include <BRepBuilderAPI_VertexInspector.hxx>
#include <StlMesh_Mesh.hxx>
#include <StlMesh_MeshTriangle.hxx>
#include <TColgp_SequenceOfXYZ.hxx>
@ -73,35 +75,58 @@ private:
void init_C_members();
void init_cache();
struct triangle_data
{
struct domain_data {
std::vector<const gp_XYZ*> vec_coords;
};
struct triangle_data {
const StlMesh_MeshTriangle* ptr_triangle;
const TColgp_SequenceOfXYZ* ptr_vec_vertices;
const domain_data* ptr_domain;
};
const StlMesh_Mesh* m_mesh;
int m_mesh_domain_count;
// Data to be used when mesh domain_count > 1
std::vector<domain_data> m_vec_domain_data;
std::vector<triangle_data> m_vec_triangle_data;
// Data to be used when mesh domain_count == 1
const StlMesh_SequenceOfMeshTriangle* m_seq_triangle;
const TColgp_SequenceOfXYZ* m_seq_vertex;
};
/*! Returns a gmio_stl_mesh_creator that will build a new domain in a
* StlMesh_Mesh object
/*! Provides creation of a new domain within an StlMesh_Mesh object
*
* The creator's cookie will point \p mesh
* gmio_stl_mesh_creator::func_add_triangle() calls
* <tt>StlMesh_Mesh::AddVertex()</tt> only for new unique vertices, ie. they
* are no vertex duplicates in the resulting domain.
*
* As of OpenCascade v7.0.0, it's not possible to rely on
* <tt>StlMesh_Mesh::AddOnlyNewVertex()</tt>: this function
* still has the same effect as <tt>StlMesh_Mesh::AddVertex()</tt>
*
* Example of use:
* \code{.cpp}
* Handle_StlMesh_Mesh occmesh = new StlMesh_Mesh;
* gmio_stl_mesh_creator_occmesh meshcreator(occmesh);
* gmio_stl_read_file(filepath, &meshcreator, &options);
* \endcode
*/
gmio_stl_mesh_creator gmio_stl_occmesh_creator(StlMesh_Mesh* mesh);
struct gmio_stl_mesh_creator_occmesh : public gmio_stl_mesh_creator
{
gmio_stl_mesh_creator_occmesh();
explicit gmio_stl_mesh_creator_occmesh(StlMesh_Mesh* mesh);
explicit gmio_stl_mesh_creator_occmesh(const Handle_StlMesh_Mesh& hnd);
/*! Same as gmio_stl_occmesh_creator(StlMesh_Mesh*) but takes a handle
*
* The creator's cookie will point to the internal data(ie StlMesh_Mesh*) of
* handle \p hnd
*/
gmio_stl_mesh_creator gmio_stl_occmesh_creator(const Handle_StlMesh_Mesh& hnd);
inline StlMesh_Mesh* mesh() const { return m_mesh; }
private:
static void begin_solid(
void* cookie, const struct gmio_stl_mesh_creator_infos* infos);
static void add_triangle(
void* cookie, uint32_t tri_id, const gmio_stl_triangle* tri);
void init_C_members();
int add_unique_vertex(const gmio_vec3f& v);
StlMesh_Mesh* m_mesh;
BRepBuilderAPI_CellFilter m_filter;
BRepBuilderAPI_VertexInspector m_inspector;
};
#endif /* GMIO_SUPPORT_STL_OCC_MESH_H */
/*! @} */

View File

@ -11,7 +11,7 @@ int main()
{
// OpenCascade
Handle_StlMesh_Mesh stlMesh;
gmio_stl_occmesh_creator(stlMesh);
gmio_stl_mesh_creator_occmesh mesh_creator(stlMesh);
// Qt
QFile file;

View File

@ -0,0 +1,21 @@
#ifndef _BRepBuilderAPI_CellFilter_HeaderFile
#define _BRepBuilderAPI_CellFilter_HeaderFile
class BRepBuilderAPI_VertexInspector;
class gp_Pnt;
class BRepBuilderAPI_CellFilter
{
public:
BRepBuilderAPI_CellFilter(double /*cellSize*/) {}
void Inspect(
const gp_Pnt& /*min_pnt*/,
const gp_Pnt& /*max_pnt*/,
BRepBuilderAPI_VertexInspector& /*inspector*/)
{}
void Add(int /*target*/, const gp_Pnt& /*pnt*/) {}
};
#endif

View File

@ -0,0 +1,27 @@
#ifndef _BRepBuilderAPI_VertexInspector_Header
#define _BRepBuilderAPI_VertexInspector_Header
#include "gp_XYZ.hxx"
#include "TColStd_ListOfInteger.hxx"
class BRepBuilderAPI_VertexInspector
{
public:
BRepBuilderAPI_VertexInspector(double /*tol*/) {}
void SetCurrent(const gp_XYZ& /*pnt*/) {}
gp_XYZ Shift(const gp_XYZ& /*pnt*/, double tol) { return gp_XYZ(); }
const TColStd_ListOfInteger& ResInd()
{
static const TColStd_ListOfInteger listInt;
return listInt;
}
void ClearResList() {}
void Add (const gp_XYZ& /*pnt*/) {}
};
#endif

View File

@ -0,0 +1,10 @@
#ifndef _Precision_HeaderFile
#define _Precision_HeaderFile
class Precision
{
public:
static double Confusion() { return 1e-6; }
};
#endif

View File

@ -17,6 +17,10 @@ public:
const double /*Xn*/, const double /*Yn*/, const double /*Zn*/)
{ return -1; }
virtual int AddVertex(
const double /*X*/, const double /*Y*/, const double /*Z*/)
{ return -1; }
virtual int AddOnlyNewVertex(
const double /*X*/, const double /*Y*/, const double /*Z*/)
{ return -1; }

View File

@ -0,0 +1,14 @@
#ifndef TColStd_ListOfInteger_HeaderFile
#define TColStd_ListOfInteger_HeaderFile
#include "Standard_TypeDef.hxx"
class TColStd_ListOfInteger
{
public:
Standard_Boolean IsEmpty() const { return Standard_True; }
int First() const { return -1; }
};
#endif

View File

@ -6,11 +6,30 @@
class TColgp_SequenceOfXYZ
{
public:
struct const_iterator
{
const gp_XYZ& operator*() const
{
static const gp_XYZ coords;
return coords;
}
const_iterator& operator++() { return *this; }
bool operator!=(const const_iterator& /*other*/) const
{ return true; }
};
int Size() const { return 0; }
const gp_XYZ& Value(const int /*Index*/) const
{
static gp_XYZ val;
return val;
}
const_iterator cbegin() const { return cend(); }
const_iterator cend() const { return const_iterator(); }
};
#endif // _TColgp_SequenceOfXYZ_HeaderFile

View File

@ -9,6 +9,7 @@ class gp_Pnt
{
public:
gp_Pnt() {}
gp_Pnt(const gp_XYZ& /*coords*/) {}
const gp_XYZ& XYZ() const { return coord; }
void Transform(const gp_Trsf&) {}

View File

@ -6,6 +6,8 @@
class gp_XYZ
{
public:
gp_XYZ() {}
gp_XYZ(Standard_Real /*x*/, Standard_Real /*y*/, Standard_Real /*z*/) {}
Standard_Real X() const { return 0.; }
Standard_Real Y() const { return 0.; }
Standard_Real Z() const { return 0.; }