diff --git a/Stream_support/include/CGAL/IO/read_3mf.h b/Stream_support/include/CGAL/IO/read_3mf.h index 5c6cf0798d2..d9e477f2820 100644 --- a/Stream_support/include/CGAL/IO/read_3mf.h +++ b/Stream_support/include/CGAL/IO/read_3mf.h @@ -1,41 +1,203 @@ +// Copyright (c) 2019 Geometry Factory +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 3 of the License, +// or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0+ +// +// Author(s) : Maxime Gimeno + #ifndef READ_3MF_H #define READ_3MF_H #include #include #include -#include "Model/COM/NMR_DLLInterfaces.h" +#include +#include +#include namespace CGAL{ -/*! - * \brief read_soups_from_3mf extracts ranges of points and triangles from the - * `MeshObject`s contained in `file_name` - * \tparam PointRanges a model of the concepts `RandomAccessContainer` and - * `BackInsertionSequence` whose `value type` is - * a model of the concepts `RandomAccessContainer` and `BackInsertionSequence` - * whose `value type` is the point type. - * \tparam PolygonRanges a model of the concept `RandomAccessContainer` whose - * `value_type` is a model of the concept `RandomAccessContainer` - * whose `value_type` is a model of the concept `RandomAccessContainer` whose - * `value_type` is std::size_t. - * \param file_name the name of the 3mf file to read. - * \param all_points a `PointRanges` that will contain the points of the meshes - * in `file_name`. - * Each of these meshes will add a range of its points. - * \param all_polygons a `PolygonRanges` that will contain the triangles of the - * meshes in `file_name`. - * Each of these meshes will add a range of its triangles. A `triangle` of - * all_polygons[i] contains the indices of its points in all_points[i]. - * \param names will contain the name of each mesh in `file_name` if any. - * If the i'th mesh has no name, it will be called "Unknown Mesh" in names. - * \return the number of meshes processed in `file_name`. - */ -template -int read_soups_from_3mf(const std::string& file_name, PointRanges& all_points, - PolygonRanges& all_polygons, std::vector& names) -{ - typedef typename PointRanges::value_type PointRange; +template +bool extract_soups (NMR::PLib3MFModelMeshObject *pMeshObject, + PointRange& points, + PolygonRange& triangles, + std::string& name) { + typedef typename PointRange::value_type Point_3; + typedef typename PolygonRange::value_type Polygon; + + HRESULT hResult; + DWORD nNeededChars; + std::vector pBuffer; + // Retrieve Mesh Name Length + hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); + if (hResult != LIB3MF_OK) + { + std::cerr<<"Error during name extraction."; + return false; + } + + // Retrieve Mesh Name + if (nNeededChars > 0) { + pBuffer.resize(nNeededChars + 1); + hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); + pBuffer[nNeededChars] = 0; + std::string temp(&pBuffer[0]); + if(temp.find("_cgal_pc") != std::string::npos + || temp.find("_cgal_pl")!= std::string::npos) //ignore point clouds and polylines + { + return false; + } + name = std::string(&pBuffer[0]); + } + else + name = std::string("Unknown Mesh"); + for(DWORD vid = 0; vid < points.size(); ++vid) + { + NMR::MODELMESHVERTEX pVertex; + NMR::lib3mf_meshobject_getvertex(pMeshObject, vid, &pVertex); + points[vid] = + Point_3(pVertex.m_fPosition[0], + pVertex.m_fPosition[1], + pVertex.m_fPosition[2]); + } + for(DWORD pid = 0; pid < triangles.size(); ++pid) + { + NMR::MODELMESHTRIANGLE pTriangle; + NMR::lib3mf_meshobject_gettriangle(pMeshObject, pid, &pTriangle); + Polygon triangle(3); + for(DWORD i = 0; i< 3; ++i) + triangle[i] = pTriangle.m_nIndices[i]; + triangles[pid] = triangle; + } + return true; +} + +template +bool extract_polylines (NMR::PLib3MFModelMeshObject *pMeshObject, + PointRange& points, + PolygonRange&, + std::string& name) { + typedef typename PointRange::value_type Point_3; + typedef typename PolygonRange::value_type Polygon; + + HRESULT hResult; + DWORD nNeededChars; + std::vector pBuffer; + // Retrieve Mesh Name Length + hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); + if (hResult != LIB3MF_OK) + { + points.resize(0); + std::cerr<<"Error during name extraction."; + return false; + } + + // Retrieve Mesh Name + if (nNeededChars > 0) { + pBuffer.resize(nNeededChars + 1); + hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); + pBuffer[nNeededChars] = 0; + std::string temp(&pBuffer[0]); + if(temp.find("_cgal_pl")== std::string::npos) //ignore not polylines + { + points.resize(0); + return false; + } + name = std::string(&pBuffer[0]); + } + else + { + points.resize(0); + return false; + } + points.resize(points.size()-3); + for(DWORD vid = 0; vid < points.size()-3; ++vid) //ignore dummy_vertices + { + NMR::MODELMESHVERTEX pVertex; + NMR::lib3mf_meshobject_getvertex(pMeshObject, vid+3, &pVertex); + points[vid] = + Point_3(pVertex.m_fPosition[0], + pVertex.m_fPosition[1], + pVertex.m_fPosition[2]); + } + return true; +} + +template +bool extract_point_clouds (NMR::PLib3MFModelMeshObject *pMeshObject, + PointRange& points, + PolygonRange&, + std::string& name) { + typedef typename PointRange::value_type Point_3; + typedef typename PolygonRange::value_type Polygon; + + HRESULT hResult; + DWORD nNeededChars; + std::vector pBuffer; + // Retrieve Mesh Name Length + hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); + if (hResult != LIB3MF_OK) + { + std::cerr<<"Error during name extraction."; + points.resize(0); + return false; + } + + // Retrieve Mesh Name + if (nNeededChars > 0) { + pBuffer.resize(nNeededChars + 1); + hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); + pBuffer[nNeededChars] = 0; + std::string temp(&pBuffer[0]); + if(temp.find("_cgal_pc")== std::string::npos) //ignore not point_cloud + { + points.resize(0); + return false; + } + name = std::string(&pBuffer[0]); + } + else{ + points.resize(0); + return false; + } + points.resize(points.size()-3); + for(DWORD vid = 0; vid < points.size()-3; ++vid) //ignore dummy_vertices + { + NMR::MODELMESHVERTEX pVertex; + NMR::lib3mf_meshobject_getvertex(pMeshObject, vid+3, &pVertex); + points[vid] = + Point_3(pVertex.m_fPosition[0], + pVertex.m_fPosition[1], + pVertex.m_fPosition[2]); + } + //ignore dummy_triangle. + return true; +} + +template +int read_from_3mf(const std::string& file_name, PointRanges& all_points, + PolygonRanges& all_polygons, std::vector& names, + std::function func + ) +{ typedef typename PointRange::value_type Point_3; - typedef typename PolygonRanges::value_type PolygonRange; typedef typename PolygonRange::value_type Polygon; DWORD nInterfaceVersionMajor, nInterfaceVersionMinor, nInterfaceVersionMicro, nbVertices, nbPolygons; HRESULT hResult; @@ -119,7 +281,6 @@ int read_soups_from_3mf(const std::string& file_name, PointRanges& all_points, NMR::lib3mf_release(pModel); return -1; } - // Query mesh interface BOOL bIsMeshObject; hResult = NMR::lib3mf_object_ismeshobject(pResource, &bIsMeshObject); @@ -132,42 +293,13 @@ int read_soups_from_3mf(const std::string& file_name, PointRanges& all_points, NMR::lib3mf_meshobject_gettrianglecount(pMeshObject, &nbPolygons); PointRange points (nbVertices); PolygonRange triangles(nbPolygons); - DWORD nNeededChars; - std::vector pBuffer; - // Retrieve Mesh Name Length - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, NULL, 0, &nNeededChars); - if (hResult != LIB3MF_OK) - return hResult; + std::string name; - // Retrieve Mesh Name - if (nNeededChars > 0) { - pBuffer.resize(nNeededChars + 1); - hResult = NMR::lib3mf_object_getnameutf8(pMeshObject, &pBuffer[0], nNeededChars + 1, NULL); - pBuffer[nNeededChars] = 0; - names.push_back(std::string(&pBuffer[0])); + if(func(pMeshObject, points, triangles, name)){ + all_points.push_back(points); + all_polygons.push_back(triangles); + names.push_back(name); } - else - names.push_back(std::string("Unknown Mesh")); - for(DWORD vid = 0; vid < nbVertices; ++vid) - { - NMR::MODELMESHVERTEX pVertex; - NMR::lib3mf_meshobject_getvertex(pMeshObject, vid, &pVertex); - points[vid] = - Point_3(pVertex.m_fPosition[0], - pVertex.m_fPosition[1], - pVertex.m_fPosition[2]); - } - for(DWORD pid = 0; pid < nbPolygons; ++pid) - { - NMR::MODELMESHTRIANGLE pTriangle; - NMR::lib3mf_meshobject_gettriangle(pMeshObject, pid, &pTriangle); - Polygon triangle(3); - for(DWORD i = 0; i< 3; ++i) - triangle[i] = pTriangle.m_nIndices[i]; - triangles[pid] = triangle; - } - all_points.push_back(points); - all_polygons.push_back(triangles); } // free instances NMR::lib3mf_release(pResource); @@ -180,6 +312,67 @@ int read_soups_from_3mf(const std::string& file_name, PointRanges& all_points, return all_points.size(); } +/*! + * \brief read_soups_from_3mf extracts ranges of points and triangles from the + * `MeshObject`s contained in `file_name` + * \tparam PointRanges a model of the concepts `RandomAccessContainer` and + * `BackInsertionSequence` whose `value type` is + * a model of the concepts `RandomAccessContainer` and `BackInsertionSequence` + * whose `value type` is the point type. + * \tparam PolygonRanges a model of the concept `RandomAccessContainer` whose + * `value_type` is a model of the concept `RandomAccessContainer` + * whose `value_type` is a model of the concept `RandomAccessContainer` whose + * `value_type` is std::size_t. + * \param file_name the name of the 3mf file to read. + * \param all_points a `PointRanges` that will contain the points of the meshes + * in `file_name`. + * Each of these meshes will add a range of its points. + * \param all_polygons a `PolygonRanges` that will contain the triangles of the + * meshes in `file_name`. + * Each of these meshes will add a range of its triangles. A `triangle` of + * all_polygons[i] contains the indices of its points in all_points[i]. + * \param names will contain the name of each mesh in `file_name` if any. + * If the i'th mesh has no name, it will be called "Unknown Mesh" in names. + * \return the number of meshes processed in `file_name`. + */ +template +int read_soups_from_3mf(const std::string& file_name, PointRanges& all_points, + PolygonRanges& all_polygons, std::vector& names + ) +{ + typedef typename PointRanges::value_type PointRange; + typedef typename PolygonRanges::value_type PolygonRange; + return read_from_3mf + (file_name, all_points, all_polygons, names, extract_soups); +} + + +template +int read_polylines_from_3mf(const std::string& file_name, PointRanges& all_points, + std::vector& names + ) +{ + typedef typename PointRanges::value_type PointRange; + typedef std::vector Polygon; + typedef std::vector PolygonRange; + std::vector all_polygons; + return read_from_3mf, PointRange, PolygonRange> + (file_name, all_points, all_polygons, names, extract_polylines); +} + + +template +int read_point_clouds_from_3mf(const std::string& file_name, PointRanges& all_points, + std::vector& names + ) +{ + typedef typename PointRanges::value_type PointRange; + typedef std::vector Polygon; + typedef std::vector PolygonRange; + std::vector all_polygons; + return read_from_3mf, PointRange, PolygonRange> + (file_name, all_points, all_polygons, names, extract_point_clouds); +} }//end CGAL #endif // READ_3MF_H diff --git a/Stream_support/test/Stream_support/CMakeLists.txt b/Stream_support/test/Stream_support/CMakeLists.txt index ca3d81698c4..f9905b79012 100644 --- a/Stream_support/test/Stream_support/CMakeLists.txt +++ b/Stream_support/test/Stream_support/CMakeLists.txt @@ -8,42 +8,23 @@ cmake_minimum_required(VERSION 3.1) find_package(CGAL QUIET) if ( CGAL_FOUND ) - set(3MF_INCLUDE_DIR "" CACHE PATH "Path to lib3MF headers") - set(3MF_LIBRARY_DIR "" CACHE PATH "Path to lib3MF library files") + find_path(3MF_INCLUDE_DIR + NAMES Common Model + DOC "Path to lib3MF headers" + ) if(IS_DIRECTORY "${3MF_INCLUDE_DIR}/Common") set(3MF_FOUND true) endif() - + find_library(3MF_LIBRARIES NAMES 3MF DOC "Path to the lib3MF library") + # create a target per cppfile file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(cppfile ${cppfiles}) if ( "${cppfile}" STREQUAL "test_3mf_to_sm.cpp" ) - if(3MF_FOUND) - if (WIN32) - set(LSUFFIX "dll") - set(LSUFFIXOUT ".dll") - elseif(UNIX AND NOT APPLE) - set(LSUFFIX "so") - set(LSUFFIXOUT ".so.1") - else() - set(LSUFFIX "dylib") - set(LSUFFIXOUT ".1.dylib") - endif() include_directories(${3MF_INCLUDE_DIR}) - link_directories(${3MF_LIBRARY_DIR}) create_single_source_cgal_program( "${cppfile}" ) - - if (WIN32) - target_link_libraries(test_3mf_to_sm PRIVATE lib3MF) - else() - # Unix prefixes the name of the library with "lib" anyway - target_link_libraries(test_3mf_to_sm PRIVATE 3MF) - if(APPLE) - target_link_directories(test_3mf_to_sm PRIVATE ${3MF_LIBRARY_DIR}/..) - endif() - endif() - + target_link_libraries(test_3mf_to_sm PRIVATE ${3MF_LIBRARIES}) else() message(STATUS "NOTICE: This program requires the lib3MF library, and will not be compiled.") endif() diff --git a/Stream_support/test/Stream_support/data/test.3mf b/Stream_support/test/Stream_support/data/test.3mf new file mode 100644 index 00000000000..223e1185b3e Binary files /dev/null and b/Stream_support/test/Stream_support/data/test.3mf differ diff --git a/Stream_support/test/Stream_support/test_3mf_to_sm.cpp b/Stream_support/test/Stream_support/test_3mf_to_sm.cpp index ee86814d079..f776128fa9c 100644 --- a/Stream_support/test/Stream_support/test_3mf_to_sm.cpp +++ b/Stream_support/test/Stream_support/test_3mf_to_sm.cpp @@ -26,7 +26,7 @@ typedef std::vector PolygonRange; int main(int argc, char** argv) { -/* if( argc != 2) + if( argc != 2) { std::cerr<<"please give an input 3mf file."; return 1; @@ -34,7 +34,8 @@ int main(int argc, char** argv) std::vector all_points; std::vector all_polygons; std::vector names; - std::size_t nb_meshes = + //testing reading functions. + int nb_meshes = CGAL::read_soups_from_3mf(argv[1], all_points, all_polygons, names); if(nb_meshes <0) return 1; @@ -61,17 +62,44 @@ int main(int argc, char** argv) ofs << mesh; ofs.close(); } - }*/ + } + all_points.clear(); + int nb_polylines = + CGAL::read_polylines_from_3mf(argv[1], all_points, names); + + if(nb_polylines == 0) + std::cout<<"No polyline found."<(sphere); CGAL::make_regular_prism(10, tube, Point_3(0,-10,0), 10); - /* all_points.clear(); all_polygons.clear(); names.clear(); - */ PointRange points; - //PolygonRange triangles; + PolygonRange triangles; typedef boost::property_map::type VPMap; VPMap vpm = get(boost::vertex_point, sphere); std::unordered_map::vertex_descriptor, @@ -82,8 +110,8 @@ int main(int argc, char** argv) points.push_back(get(vpm, v)); vertex_id_map[v] = i++; } - //all_points.push_back(points); - /*for(auto f : sphere.faces()) + all_points.push_back(points); + for(auto f : sphere.faces()) { Polygon triangle; for(auto vert : CGAL::vertices_around_face(halfedge(f, sphere), sphere)) @@ -117,30 +145,30 @@ int main(int argc, char** argv) all_polygons.push_back(triangles); names.push_back(std::string("sphere")); names.push_back(std::string("tube")); - if(!CGAL::write_soups_to_3mf("micro.3mf", all_points, all_polygons, names)){ - std::cerr<<"an error has occured in final writing."<