diff --git a/benchmarks/benchmark_opencascade/CMakeLists.txt b/benchmarks/benchmark_opencascade/CMakeLists.txt index 767ed84..74d3745 100644 --- a/benchmarks/benchmark_opencascade/CMakeLists.txt +++ b/benchmarks/benchmark_opencascade/CMakeLists.txt @@ -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}) diff --git a/benchmarks/benchmark_opencascade/main.cpp b/benchmarks/benchmark_opencascade/main.cpp index 6bb6e01..25ded90 100644 --- a/benchmarks/benchmark_opencascade/main.cpp +++ b/benchmarks/benchmark_opencascade/main.cpp @@ -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(filepath), &mesh_creator, NULL); if (error != GMIO_ERROR_OK) diff --git a/examples/occstl_read_file.cpp b/examples/occstl_read_file.cpp index 3fbedc5..13c2ce2 100644 --- a/examples/occstl_read_file.cpp +++ b/examples/occstl_read_file.cpp @@ -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); diff --git a/examples/occstl_redefine_mesh_creator.cpp b/examples/occstl_redefine_mesh_creator.cpp index fa7ab65..b96739d 100644 --- a/examples/occstl_redefine_mesh_creator.cpp +++ b/examples/occstl_redefine_mesh_creator.cpp @@ -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(cookie); + static_cast(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(cookie); + static_cast(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; diff --git a/src/gmio_support/stl_occ_mesh.cpp b/src/gmio_support/stl_occ_mesh.cpp index af41188..15b4f8e 100644 --- a/src/gmio_support/stl_occ_mesh.cpp +++ b/src/gmio_support/stl_occ_mesh.cpp @@ -18,49 +18,19 @@ #include "stl_occ_utils.h" #include +#include +#include #include #include #include #include -namespace internal { - -static void occmesh_add_triangle( - void* cookie, uint32_t tri_id, const gmio_stl_triangle* tri) -{ - StlMesh_Mesh* mesh = static_cast(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(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 triangle_data& tridata = it->m_vec_triangle_data.at(tri_id); + const std::vector& 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) { - 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; - m_vec_triangle_data.push_back(std::move(tridata)); - } + // Fill vector of triangle data + m_vec_triangle_data.reserve(this->triangle_count); + 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); + 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_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(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(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; } diff --git a/src/gmio_support/stl_occ_mesh.h b/src/gmio_support/stl_occ_mesh.h index 255b95e..4ded514 100644 --- a/src/gmio_support/stl_occ_mesh.h +++ b/src/gmio_support/stl_occ_mesh.h @@ -23,7 +23,7 @@ * * Of course this requires the includepath and libpath to point to OpenCascade, * the import libraries likely needed are:\n - * TKernel TKMath TKSTL + * TKernel TKMath TKSTL TKTopAlgo * * \addtogroup gmio_support * @{ @@ -42,6 +42,8 @@ #include +#include +#include #include #include #include @@ -50,7 +52,7 @@ * * gmio_stl_mesh_occmesh iterates efficiently over the triangles of all * domains. - * + * * Example of use: * \code{.cpp} * const Handle_StlMesh_Mesh occmesh = ...; @@ -73,35 +75,58 @@ private: void init_C_members(); void init_cache(); - struct triangle_data - { + struct domain_data { + std::vector 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 m_vec_domain_data; std::vector 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 + * StlMesh_Mesh::AddVertex() 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 + * StlMesh_Mesh::AddOnlyNewVertex(): this function + * still has the same effect as StlMesh_Mesh::AddVertex() + * + * 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 */ /*! @} */ diff --git a/tests/fake_support/main.cpp b/tests/fake_support/main.cpp index c14aa8e..bd60459 100644 --- a/tests/fake_support/main.cpp +++ b/tests/fake_support/main.cpp @@ -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; diff --git a/tests/fake_support/opencascade/BRepBuilderAPI_CellFilter.hxx b/tests/fake_support/opencascade/BRepBuilderAPI_CellFilter.hxx new file mode 100644 index 0000000..a112635 --- /dev/null +++ b/tests/fake_support/opencascade/BRepBuilderAPI_CellFilter.hxx @@ -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 diff --git a/tests/fake_support/opencascade/BRepBuilderAPI_VertexInspector.hxx b/tests/fake_support/opencascade/BRepBuilderAPI_VertexInspector.hxx new file mode 100644 index 0000000..503ef46 --- /dev/null +++ b/tests/fake_support/opencascade/BRepBuilderAPI_VertexInspector.hxx @@ -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 diff --git a/tests/fake_support/opencascade/Precision.hxx b/tests/fake_support/opencascade/Precision.hxx new file mode 100644 index 0000000..08ef655 --- /dev/null +++ b/tests/fake_support/opencascade/Precision.hxx @@ -0,0 +1,10 @@ +#ifndef _Precision_HeaderFile +#define _Precision_HeaderFile + +class Precision +{ +public: + static double Confusion() { return 1e-6; } +}; + +#endif diff --git a/tests/fake_support/opencascade/StlMesh_Mesh.hxx b/tests/fake_support/opencascade/StlMesh_Mesh.hxx index 8884334..a78b9d8 100644 --- a/tests/fake_support/opencascade/StlMesh_Mesh.hxx +++ b/tests/fake_support/opencascade/StlMesh_Mesh.hxx @@ -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; } diff --git a/tests/fake_support/opencascade/TColStd_ListOfInteger.hxx b/tests/fake_support/opencascade/TColStd_ListOfInteger.hxx new file mode 100644 index 0000000..034b3af --- /dev/null +++ b/tests/fake_support/opencascade/TColStd_ListOfInteger.hxx @@ -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 diff --git a/tests/fake_support/opencascade/TColgp_SequenceOfXYZ.hxx b/tests/fake_support/opencascade/TColgp_SequenceOfXYZ.hxx index 3321660..5210870 100644 --- a/tests/fake_support/opencascade/TColgp_SequenceOfXYZ.hxx +++ b/tests/fake_support/opencascade/TColgp_SequenceOfXYZ.hxx @@ -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 diff --git a/tests/fake_support/opencascade/gp_Pnt.hxx b/tests/fake_support/opencascade/gp_Pnt.hxx index 3360a86..be4ce4f 100644 --- a/tests/fake_support/opencascade/gp_Pnt.hxx +++ b/tests/fake_support/opencascade/gp_Pnt.hxx @@ -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&) {} diff --git a/tests/fake_support/opencascade/gp_XYZ.hxx b/tests/fake_support/opencascade/gp_XYZ.hxx index dd0fbaf..7cf7d27 100644 --- a/tests/fake_support/opencascade/gp_XYZ.hxx +++ b/tests/fake_support/opencascade/gp_XYZ.hxx @@ -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.; }