mirror of https://github.com/CGAL/cgal
Rework Surface_mesh IO
This commit is contained in:
parent
65c1a4f81b
commit
b1da380064
|
|
@ -7,6 +7,7 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Maxime Gimeno
|
||||
// Mael Rouxel-Labbé
|
||||
|
||||
#ifndef CGAL_BGL_IO_GENERIC_FACEGRAPH_BUILDER_H
|
||||
#define CGAL_BGL_IO_GENERIC_FACEGRAPH_BUILDER_H
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ public:
|
|||
if(has_face_colors)
|
||||
{
|
||||
const CGAL::Color& fc = get(fcm, f);
|
||||
m_writer.write_face_normal(fc.red(), fc.green(), fc.blue());
|
||||
m_writer.write_face_color(fc.red(), fc.green(), fc.blue());
|
||||
}
|
||||
|
||||
m_writer.write_facet_end();
|
||||
|
|
|
|||
|
|
@ -60,28 +60,10 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace IO
|
||||
|
||||
/*!
|
||||
\ingroup PkgBGLIOFct
|
||||
|
||||
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash, and lines with whitespace.
|
||||
|
||||
\cgalNamedParamsBegin
|
||||
\cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
|
||||
If this parameter is omitted, an internal property map for
|
||||
`CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
\sa Overloads of this function for specific models of the concept `FaceGraph`.
|
||||
|
||||
\pre The data must represent a 2-manifold
|
||||
|
||||
\see \ref IOStreamOFF
|
||||
*/
|
||||
// Because some packages can provide overloads with the same signature to automatically initialize
|
||||
// property maps (see Surface_mesh/IO/ for example)
|
||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(std::istream& in,
|
||||
bool read_OFF_BGL(std::istream& in,
|
||||
FaceGraph& g,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
|
|
@ -92,24 +74,36 @@ bool read_OFF(std::istream& in,
|
|||
return builder(g, np);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace IO
|
||||
|
||||
/*!
|
||||
\ingroup PkgBGLIOFct
|
||||
|
||||
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash,
|
||||
and lines with whitespace.
|
||||
|
||||
\sa Overloads of this function for specific models of the concept `FaceGraph`.
|
||||
\cgalNamedParamsBegin
|
||||
\cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `g`.
|
||||
If this parameter is omitted, an internal property map for
|
||||
`CGAL::vertex_point_t` should be available in `FaceGraph`\cgalParamEnd
|
||||
\cgalNamedParamsEnd
|
||||
|
||||
\pre The data must represent a 2-manifold
|
||||
|
||||
\attention The graph `g` is not cleared, and the data from the stream are added.
|
||||
\sa Overloads of this function for specific models of the concept `FaceGraph`.
|
||||
|
||||
\see \ref IOStreamOFF
|
||||
*/
|
||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(const char* fname,
|
||||
FaceGraph& g,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
bool read_OFF(std::istream& in, FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
return IO::internal::read_OFF_BGL(in, g, np);
|
||||
}
|
||||
|
||||
// document that too
|
||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(const char* fname, FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
std::ifstream in(fname);
|
||||
return read_OFF(in, g, np);
|
||||
|
|
@ -132,6 +126,21 @@ bool read_OFF(const std::string& fname, FaceGraph& g) { return read_OFF(fname, g
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Write
|
||||
|
||||
namespace IO {
|
||||
namespace internal {
|
||||
|
||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF_BGL(std::ostream& os,
|
||||
const FaceGraph& g,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
IO::internal::Generic_facegraph_printer<std::ostream, FaceGraph, CGAL::File_writer_OFF> printer(os);
|
||||
return printer(g, np);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace IO
|
||||
|
||||
/*!
|
||||
\ingroup PkgBGLIOFct
|
||||
|
||||
|
|
@ -149,27 +158,14 @@ bool read_OFF(const std::string& fname, FaceGraph& g) { return read_OFF(fname, g
|
|||
\see \ref IOStreamOFF
|
||||
*/
|
||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF(std::ostream& os,
|
||||
const FaceGraph& g,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
bool write_OFF(std::ostream& os, const FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
IO::internal::Generic_facegraph_printer<std::ostream, FaceGraph, CGAL::File_writer_OFF> printer(os);
|
||||
return printer(g, np);
|
||||
return IO::internal::write_OFF_BGL(os, g, np);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgBGLIOFct
|
||||
|
||||
writes the graph `g` in the OFF format into a file named `fname`.
|
||||
|
||||
\sa Overloads of this function for specific models of the concept `FaceGraph`.
|
||||
|
||||
\see \ref IOStreamOFF
|
||||
*/
|
||||
// document that too
|
||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF(const char* fname,
|
||||
const FaceGraph& g,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
bool write_OFF(const char* fname, const FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
std::ofstream out(fname);
|
||||
return write_OFF(out, g, np);
|
||||
|
|
@ -181,7 +177,7 @@ bool write_OFF(const std::string& fname, const FaceGraph& g, const CGAL_BGL_NP_C
|
|||
return write_OFF(fname.c_str(), g, np);
|
||||
}
|
||||
|
||||
template <typename Input, typename FaceGraph>
|
||||
template <typename FaceGraph>
|
||||
bool write_OFF(std::ostream& os, const FaceGraph& g) { return write_OFF(os, g, parameters::all_default()); }
|
||||
template <typename FaceGraph>
|
||||
bool write_OFF(const char* fname, const FaceGraph& g) { return write_OFF(fname, g, parameters::all_default()); }
|
||||
|
|
|
|||
|
|
@ -99,6 +99,8 @@ create_single_source_cgal_program( "test_Properties.cpp" )
|
|||
|
||||
create_single_source_cgal_program( "test_wrl.cpp" )
|
||||
|
||||
create_single_source_cgal_program( "test_io.cpp" )
|
||||
|
||||
if(OpenMesh_FOUND)
|
||||
target_link_libraries( test_clear PRIVATE ${OPENMESH_LIBRARIES})
|
||||
target_link_libraries( test_Euler_operations PRIVATE ${OPENMESH_LIBRARIES})
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include <CGAL/IO/OFF.h>
|
||||
#include <CGAL/IO/OBJ.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include "Scene_points_with_normal_item.h"
|
||||
|
||||
#include <CGAL/IO/PLY.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/Three/Polyhedron_demo_io_plugin_interface.h>
|
||||
#include <CGAL/Three/Three.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1510,9 +1510,14 @@ Scene_surface_mesh_item::load_obj(std::istream& in)
|
|||
bool
|
||||
Scene_surface_mesh_item::save_obj(std::ostream& out) const
|
||||
{
|
||||
CGAL::File_writer_wavefront writer;
|
||||
CGAL::generic_print_surface_mesh(out, *(d->smesh_), writer);
|
||||
return out.good();
|
||||
typename SMesh::template Property_map<typename SMesh::Vertex_index, EPICK::Vector_3> vnormals;
|
||||
bool has_normals = false;
|
||||
boost::tie(vnormals, has_normals) = M.template property_map<typename SMesh::Vertex_index, EPICK::Vector_3>("v:normal");
|
||||
|
||||
if(has_normals)
|
||||
return CGAL::write_OBJ(out, *(d->smesh_), parameters::normal_map(vnormals));
|
||||
else
|
||||
return CGAL::write_OBJ(out, *(d->smesh_));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -461,12 +461,12 @@ struct Constant_property_map
|
|||
Constant_property_map(const value_type& default_value = value_type()) : default_value (default_value) { }
|
||||
|
||||
/// Free function that returns `pm.default_value`.
|
||||
inline friend value_type
|
||||
get (const Constant_property_map& pm, const key_type&){ return pm.default_value; }
|
||||
inline friend
|
||||
const value_type& get (const Constant_property_map& pm, const key_type&) { return pm.default_value; }
|
||||
|
||||
/// Free function that does nothing.
|
||||
inline friend void
|
||||
put (const Constant_property_map&, const key_type&, const value_type&) { }
|
||||
inline friend
|
||||
void put (const Constant_property_map&, const key_type&, const value_type&) { }
|
||||
};
|
||||
|
||||
/// \ingroup PkgPropertyMapRef
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ public:
|
|||
bool operator()(std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons)
|
||||
{
|
||||
if(m_out.fail())
|
||||
return false;
|
||||
|
||||
m_writer.write_header(m_out, points.size(), 0, polygons.size());
|
||||
for(std::size_t i=0, end=points.size(); i<end; ++i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ namespace CGAL {
|
|||
namespace IO {
|
||||
namespace internal {
|
||||
|
||||
template <typename Points, typename Faces, typename VertexNormalOutputIterator>
|
||||
bool read_OBJ(std::istream& input,
|
||||
Points& points,
|
||||
Faces& faces,
|
||||
template <typename PointRange, typename PolygonRange, typename VertexNormalOutputIterator>
|
||||
bool read_OBJ(std::istream& is,
|
||||
PointRange& points,
|
||||
PolygonRange& faces,
|
||||
VertexNormalOutputIterator vn_out)
|
||||
{
|
||||
typedef typename boost::range_value<Points>::type Point;
|
||||
typedef typename boost::range_value<PointRange>::type Point;
|
||||
typedef typename CGAL::Kernel_traits<Point>::Kernel Kernel;
|
||||
typedef typename Kernel::Vector_3 Normal;
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ bool read_OBJ(std::istream& input,
|
|||
Point p;
|
||||
std::string line;
|
||||
|
||||
while(getline(input, line))
|
||||
while(getline(is, line))
|
||||
{
|
||||
if(line[0] == 'v' && line[1] == ' ')
|
||||
{
|
||||
|
|
@ -106,7 +106,7 @@ bool read_OBJ(std::istream& input,
|
|||
return false;
|
||||
}
|
||||
|
||||
return !input.fail();
|
||||
return !is.fail();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
|
@ -114,16 +114,16 @@ bool read_OBJ(std::istream& input,
|
|||
|
||||
//! \ingroup IOstreamFunctions
|
||||
//!
|
||||
/// reads the content of `input` into `points` and `faces`, using the `OBJ` format.
|
||||
/// reads the content of `is` into `points` and `faces`, using the `OBJ` format.
|
||||
///
|
||||
/// \tparam Points a `RandomAccessContainer` of `Point_3,
|
||||
/// \tparam Faces a `RandomAccessContainer` of `RandomAccessContainer` of `std::size_t`
|
||||
///
|
||||
/// \see \ref IOStreamOBJ
|
||||
template <typename Points, typename Faces, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
template <typename PointRange, typename PolygonRange, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OBJ(std::istream& is,
|
||||
Points& points,
|
||||
Faces& faces,
|
||||
PointRange& points,
|
||||
PolygonRange& faces,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
using parameters::choose_parameter;
|
||||
|
|
@ -134,11 +134,44 @@ bool read_OBJ(std::istream& is,
|
|||
CGAL::Emptyset_iterator()));
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OBJ(const char* fname,
|
||||
PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
std::ifstream in(fname);
|
||||
return read_OBJ(in, points, polygons, np);
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OBJ(const std::string& fname, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
return read_OBJ(fname.c_str(), points, polygons, np);
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool read_OBJ(std::istream& is, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return read_OBJ(is, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool read_OBJ(const char* fname, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return read_OBJ(fname, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool read_OBJ(const std::string& fname, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return read_OBJ(fname, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Write
|
||||
|
||||
|
||||
/*!
|
||||
* \ingroup IOstreamFunctions
|
||||
*
|
||||
|
|
@ -146,15 +179,28 @@ bool read_OBJ(std::istream& is,
|
|||
*
|
||||
* \see \ref IOStreamOBJ
|
||||
*/
|
||||
template <class Point_3, class Polygon_3>
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool write_OBJ(std::ostream& os,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons)
|
||||
PointRange& points,
|
||||
PolygonRange& polygons)
|
||||
{
|
||||
Generic_writer<std::ostream, File_writer_wavefront> writer(os); // @fixme uniformize os and out
|
||||
Generic_writer<std::ostream, File_writer_wavefront> writer(os);
|
||||
return writer(points, polygons);
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool write_OBJ(const char* fname, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
std::ofstream out(fname);
|
||||
return write_OBJ(out, points, polygons);
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool write_OBJ(const std::string& fname, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return write_OBJ(fname.c_str(), points, polygons);
|
||||
}
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_IO_OBJ_H
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public:
|
|||
}
|
||||
void write_facet_begin(std::size_t) { out() << "f "; }
|
||||
void write_facet_vertex_index(std::size_t idx) { out() << ' ' << idx+1; }
|
||||
void write_face_normal(const double, const double, const double) { }
|
||||
void write_face_color(const double, const double, const double) { }
|
||||
void write_facet_end() { out() << '\n'; }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/use.h>
|
||||
|
||||
#include <boost/range/value_type.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
|
@ -36,26 +38,29 @@ namespace CGAL {
|
|||
namespace IO {
|
||||
namespace internal {
|
||||
|
||||
template <typename Point_3, typename Polygon_3,
|
||||
template <typename PointRange, typename PolygonRange,
|
||||
typename VertexNormalOutputIterator,
|
||||
typename VertexColorOutputIterator,
|
||||
typename VertexTextureOutputIterator,
|
||||
typename FaceColorOutputIterator>
|
||||
bool read_OFF(std::istream& in,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons,
|
||||
bool read_OFF(std::istream& is,
|
||||
PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
VertexNormalOutputIterator vn_out,
|
||||
VertexColorOutputIterator vc_out,
|
||||
VertexTextureOutputIterator vt_out,
|
||||
FaceColorOutputIterator fc_out)
|
||||
|
||||
{
|
||||
typedef typename CGAL::Kernel_traits<Point_3>::Kernel Kernel;
|
||||
typedef typename boost::range_value<PointRange>::type Point;
|
||||
typedef typename CGAL::Kernel_traits<Point>::Kernel Kernel;
|
||||
typedef typename Kernel::Point_2 Texture;
|
||||
typedef typename Kernel::Vector_3 Normal;
|
||||
typedef CGAL::Color Color;
|
||||
|
||||
CGAL::File_scanner_OFF scanner(in);
|
||||
if(!is.good())
|
||||
return false;
|
||||
|
||||
CGAL::File_scanner_OFF scanner(is);
|
||||
|
||||
points.resize(scanner.size_of_vertices());
|
||||
polygons.resize(scanner.size_of_facets());
|
||||
|
|
@ -82,7 +87,6 @@ bool read_OFF(std::istream& in,
|
|||
*vc_out++ = Color(r,g,b);
|
||||
}
|
||||
|
||||
// @fixme
|
||||
if(scanner.has_textures())
|
||||
{
|
||||
double nx, ny, nw;
|
||||
|
|
@ -93,7 +97,7 @@ bool read_OFF(std::istream& in,
|
|||
|
||||
scanner.skip_to_next_vertex(i);
|
||||
|
||||
if(!in.good())
|
||||
if(!is.good())
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +107,7 @@ bool read_OFF(std::istream& in,
|
|||
std::size_t no;
|
||||
scanner.scan_facet(no, i);
|
||||
|
||||
if(!in.good())
|
||||
if(!is.good())
|
||||
return false;
|
||||
|
||||
IO::internal::resize(polygons[i], no);
|
||||
|
|
@ -120,7 +124,7 @@ bool read_OFF(std::istream& in,
|
|||
if(i == 0)
|
||||
{
|
||||
std::string col;
|
||||
std::getline(in, col);
|
||||
std::getline(is, col);
|
||||
std::istringstream iss(col);
|
||||
char ci =' ';
|
||||
|
||||
|
|
@ -139,7 +143,7 @@ bool read_OFF(std::istream& in,
|
|||
}
|
||||
}
|
||||
|
||||
return !in.fail();
|
||||
return !is.fail();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
|
@ -148,22 +152,22 @@ bool read_OFF(std::istream& in,
|
|||
/*!
|
||||
* \ingroup IOstreamFunctions
|
||||
*
|
||||
* reads the content of `in` into `points` and `polygons`, in the OFF format.
|
||||
* reads the content of `is` into `points` and `polygons`, in the OFF format.
|
||||
*
|
||||
* @fixme re-add support for STOFF
|
||||
*
|
||||
* \see \ref IOStreamOFF
|
||||
*/
|
||||
template <typename Point_3, typename Polygon_3, typename NamedParameters>
|
||||
bool read_OFF(std::istream& in,
|
||||
std::vector<Point_3>& points, // @fixme doesn't need a vector specifically
|
||||
std::vector<Polygon_3>& polygons,
|
||||
template <typename PointRange, typename PolygonRange, typename NamedParameters>
|
||||
bool read_OFF(std::istream& is,
|
||||
PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
|
||||
return IO::internal::read_OFF(in, points, polygons,
|
||||
return IO::internal::read_OFF(is, points, polygons,
|
||||
choose_parameter(get_parameter(np, internal_np::vertex_normal_output_iterator),
|
||||
CGAL::Emptyset_iterator()),
|
||||
choose_parameter(get_parameter(np, internal_np::vertex_color_output_iterator),
|
||||
|
|
@ -174,45 +178,36 @@ bool read_OFF(std::istream& in,
|
|||
CGAL::Emptyset_iterator()));
|
||||
}
|
||||
|
||||
template <typename Point_3, typename Polygon_3, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
template <typename PointRange, typename PolygonRange, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(const char* fname,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons,
|
||||
PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
std::ifstream in(fname);
|
||||
return read_OFF(in, points, polygons, np);
|
||||
}
|
||||
|
||||
template <typename Point_3, typename Polygon_3, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(const std::string& fname,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
template <typename PointRange, typename PolygonRange, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(const std::string& fname, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
return read_OFF(fname.c_str(), points, polygons, np);
|
||||
}
|
||||
|
||||
template <typename Point_3, typename Polygon_3>
|
||||
bool read_OFF(std::istream& is,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons)
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool read_OFF(std::istream& is, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return read_OFF(is, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
||||
template <typename Point_3, typename Polygon_3>
|
||||
bool read_OFF(const char* fname,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons)
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool read_OFF(const char* fname, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return read_OFF(fname, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
||||
template <typename Point_3, typename Polygon_3>
|
||||
bool read_OFF(const std::string& fname,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons)
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool read_OFF(const std::string& fname, PointRange& points, PolygonRange& polygons)
|
||||
{
|
||||
return read_OFF(fname, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
|
@ -228,20 +223,20 @@ bool read_OFF(const std::string& fname,
|
|||
*
|
||||
* \see \ref IOStreamOFF
|
||||
*/
|
||||
template <typename Point_3, typename Polygon_3, typename NamedParameters>
|
||||
template <typename PointRange, typename PolygonRange, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF(std::ostream& os,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons,
|
||||
const NamedParameters& np)
|
||||
PointRange& points,
|
||||
PolygonRange& polygons,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
Generic_writer<std::ostream, File_writer_OFF> writer(os);
|
||||
return writer(points, polygons, np);
|
||||
}
|
||||
|
||||
template <class Point_3, class Polygon_3>
|
||||
template <typename PointRange, typename PolygonRange>
|
||||
bool write_OFF(std::ostream& os,
|
||||
std::vector<Point_3>& points,
|
||||
std::vector<Polygon_3>& polygons)
|
||||
PointRange& points,
|
||||
PolygonRange& polygons)
|
||||
{
|
||||
return write_OFF(os, points, polygons, parameters::all_default());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,14 +91,29 @@ public:
|
|||
|
||||
void write_vertex_color(const double r, const double g, const double b)
|
||||
{
|
||||
// @todo
|
||||
CGAL_assertion(false);
|
||||
if(m_header.binary())
|
||||
{
|
||||
I_Binary_write_big_endian_float32(out(), float(r));
|
||||
I_Binary_write_big_endian_float32(out(), float(g));
|
||||
I_Binary_write_big_endian_float32(out(), float(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
out() << ' ' << ' ' << r << ' ' << g << ' ' << b;
|
||||
}
|
||||
}
|
||||
|
||||
void write_vertex_texture(const double, const double)
|
||||
void write_vertex_texture(const double tx, const double ty)
|
||||
{
|
||||
// @todo
|
||||
CGAL_assertion(false);
|
||||
if(m_header.binary())
|
||||
{
|
||||
I_Binary_write_big_endian_float32(out(), float(tx));
|
||||
I_Binary_write_big_endian_float32(out(), float(ty));
|
||||
}
|
||||
else
|
||||
{
|
||||
out() << ' ' << ' ' << tx << ' ' << ty;
|
||||
}
|
||||
}
|
||||
|
||||
void write_facet_header()
|
||||
|
|
@ -135,7 +150,7 @@ public:
|
|||
out() << ' ' << index;
|
||||
}
|
||||
|
||||
void write_face_normal(const double, const double, const double) { }
|
||||
void write_face_color(const double, const double, const double) { }
|
||||
|
||||
void write_facet_end()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -397,7 +397,10 @@ returns the printing mode of the %IO stream `s`.
|
|||
\sa `CGAL::is_binary()`
|
||||
\sa `CGAL::is_pretty()`
|
||||
*/
|
||||
CGAL_EXPORT inline IO::Mode get_mode(std::ios& i) { return static_cast<IO::Mode>(i.iword(IO::Static::get_mode())); }
|
||||
inline IO::Mode get_mode(std::ios& i)
|
||||
{
|
||||
return static_cast<IO::Mode>(i.iword(IO::Static::get_mode()));
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup PkgStreamSupportRef
|
||||
|
|
@ -414,7 +417,7 @@ Returns the previous mode of `s`.
|
|||
\sa `CGAL::is_binary()`
|
||||
\sa `CGAL::is_pretty()`
|
||||
*/
|
||||
CGAL_EXPORT inline IO::Mode set_ascii_mode(std::ios& i)
|
||||
inline IO::Mode set_ascii_mode(std::ios& i)
|
||||
{
|
||||
IO::Mode m = get_mode(i);
|
||||
i.iword(IO::Static::get_mode()) = IO::ASCII;
|
||||
|
|
@ -436,7 +439,7 @@ Returns the previous mode of `s`.
|
|||
\sa `CGAL::is_binary()`
|
||||
\sa `CGAL::is_pretty()`
|
||||
*/
|
||||
CGAL_EXPORT inline IO::Mode set_binary_mode(std::ios& i)
|
||||
inline IO::Mode set_binary_mode(std::ios& i)
|
||||
{
|
||||
IO::Mode m = get_mode(i);
|
||||
i.iword(IO::Static::get_mode()) = IO::BINARY;
|
||||
|
|
@ -458,7 +461,7 @@ Returns the previous mode of `s`.
|
|||
\sa `CGAL::is_binary()`
|
||||
\sa `CGAL::is_pretty()`
|
||||
*/
|
||||
CGAL_EXPORT inline IO::Mode set_pretty_mode(std::ios& i) //@todo export ?
|
||||
inline IO::Mode set_pretty_mode(std::ios& i)
|
||||
{
|
||||
IO::Mode m = get_mode(i);
|
||||
i.iword(IO::Static::get_mode()) = IO::PRETTY;
|
||||
|
|
@ -479,7 +482,7 @@ sets the printing mode of the %IO stream `s`.
|
|||
\sa `CGAL::is_binary()`
|
||||
\sa `CGAL::is_pretty()`
|
||||
*/
|
||||
CGAL_EXPORT inline IO::Mode set_mode(std::ios& i, IO::Mode m)
|
||||
inline IO::Mode set_mode(std::ios& i, IO::Mode m)
|
||||
{
|
||||
IO::Mode old = get_mode(i);
|
||||
i.iword(IO::Static::get_mode()) = m;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
namespace CGAL {
|
||||
|
||||
// fwdS for the public interface
|
||||
template<typename K>
|
||||
template<typename P>
|
||||
class Surface_mesh;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,15 @@
|
|||
|
||||
#include <CGAL/license/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/use.h>
|
||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/Surface_mesh/Properties.h>
|
||||
|
||||
#include <CGAL/Surface_mesh/IO/3mf.h>
|
||||
#include <CGAL/Surface_mesh/IO/OFF.h>
|
||||
#include <CGAL/Surface_mesh/IO/PLY.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
|
||||
#include <CGAL/use.h>
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
|
|
@ -34,194 +37,7 @@
|
|||
|
||||
namespace CGAL {
|
||||
|
||||
namespace internal {
|
||||
// helper function
|
||||
template <typename T> void read(std::istream& in, T& t)
|
||||
{
|
||||
in.read(reinterpret_cast<char*>(&t), sizeof(t));
|
||||
}
|
||||
|
||||
template <typename Point_3>
|
||||
bool read_off_binary(Surface_mesh<Point_3>& mesh,
|
||||
std::istream& in,
|
||||
const bool has_normals,
|
||||
const bool has_texcoords)
|
||||
{
|
||||
typedef Surface_mesh<Point_3> Mesh;
|
||||
typedef typename Kernel_traits<Point_3>::Kernel K;
|
||||
typedef typename K::Vector_3 Vector_3;
|
||||
typedef typename K::Vector_2 Vector_2;
|
||||
typedef typename K::Vector_3 Normal;
|
||||
typedef typename K::Vector_3 Texture_coordinate;
|
||||
|
||||
unsigned int i, j, idx;
|
||||
unsigned int nV, nF, nE;
|
||||
Point_3 p;
|
||||
Vector_3 n, c;
|
||||
Vector_2 t;
|
||||
typename Mesh::Vertex_index v;
|
||||
|
||||
// properties
|
||||
typename Mesh::template Property_map<typename Mesh::Vertex_index, Normal> normals;
|
||||
typename Mesh::template Property_map<typename Mesh::Vertex_index, Texture_coordinate> texcoords;
|
||||
if(has_normals) normals = mesh.template add_property_map<typename Mesh::Vertex_index, Normal>("v:normal").first;
|
||||
if(has_texcoords) texcoords = mesh.template add_property_map<typename Mesh::Vertex_index, Texture_coordinate>("v:texcoord").first;
|
||||
|
||||
// #Vertice, #Faces, #Edges
|
||||
internal::read(in, nV);
|
||||
internal::read(in, nF);
|
||||
internal::read(in, nE);
|
||||
mesh.clear();
|
||||
mesh.reserve(nV, (std::max)(3*nV, nE), nF);
|
||||
|
||||
// read vertices: pos [normal] [color] [texcoord]
|
||||
for(i=0; i<nV && in.good(); ++i)
|
||||
{
|
||||
// position
|
||||
internal::read(in, p);
|
||||
v = mesh.add_vertex(p);
|
||||
|
||||
// normal
|
||||
if(has_normals)
|
||||
{
|
||||
internal::read(in, n);
|
||||
normals[v] = n;
|
||||
}
|
||||
|
||||
// tex coord
|
||||
if(has_texcoords)
|
||||
{
|
||||
internal::read(in, t);
|
||||
texcoords[v] = Vector_3(t[0], t[1], 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// read faces: #N v[1] v[2] ... v[n-1]
|
||||
std::vector<typename Mesh::Vertex_index> vertices;
|
||||
for(i=0; i<nF; ++i)
|
||||
{
|
||||
internal::read(in, nV);
|
||||
vertices.resize(nV);
|
||||
for(j=0; j<nV; ++j)
|
||||
{
|
||||
internal::read(in, idx);
|
||||
vertices[j] = typename Mesh::Vertex_index(idx);
|
||||
}
|
||||
if(!mesh.add_face(vertices).is_valid()) {
|
||||
// adding a face did not succeed, stop reading the rest
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Point_3>
|
||||
bool read_off_ascii(Surface_mesh<Point_3>& mesh,
|
||||
std::istream& in,
|
||||
const bool has_normals,
|
||||
const bool has_texcoords)
|
||||
{
|
||||
typedef Surface_mesh<Point_3> Mesh;
|
||||
typedef typename Kernel_traits<Point_3>::Kernel K;
|
||||
typedef typename K::Vector_3 Vector_3;
|
||||
typedef typename K::Vector_3 Normal;
|
||||
typedef typename K::Vector_3 Texture_coordinate;
|
||||
|
||||
boost::array<double, 3> buffer;
|
||||
std::string line;
|
||||
unsigned int i, j, idx;
|
||||
unsigned int nV, nF, nE;
|
||||
typename Mesh::Vertex_index v;
|
||||
|
||||
// properties
|
||||
typename Mesh::template Property_map<typename Mesh::Vertex_index, Normal> normals;
|
||||
typename Mesh::template Property_map<typename Mesh::Vertex_index, Texture_coordinate> texcoords;
|
||||
|
||||
if(has_normals) normals = mesh.template add_property_map<typename Mesh::Vertex_index, Normal>("v:normal").first;
|
||||
if(has_texcoords) texcoords = mesh.template add_property_map<typename Mesh::Vertex_index, Texture_coordinate>("v:texcoord").first;
|
||||
|
||||
char c;
|
||||
do {
|
||||
c = in.get();
|
||||
if(c == '#'){
|
||||
getline(in,line);
|
||||
} else {
|
||||
in.putback(c);
|
||||
break;
|
||||
}
|
||||
}while(1);
|
||||
|
||||
// #Vertice, #Faces, #Edges
|
||||
in >> nV >> nF >> nE;
|
||||
getline(in,line); // reads eol
|
||||
|
||||
mesh.clear();
|
||||
mesh.reserve(nV, (std::max)(3*nV, nE), nF);
|
||||
|
||||
// read vertices: pos [normal] [color] [texcoord]
|
||||
for(i=0; i<nV && in.good(); ++i)
|
||||
{
|
||||
// read line
|
||||
getline(in, line);
|
||||
if(line[0] == '#') // if the first column is a # we are looking at a comment line
|
||||
{
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// position
|
||||
std::istringstream iss(line);
|
||||
iss >> iformat(buffer[0]) >> iformat(buffer[1]) >> iformat(buffer[2]);
|
||||
v = mesh.add_vertex(Point_3(buffer[0], buffer[1], buffer[2]));
|
||||
|
||||
// normal
|
||||
if(has_normals)
|
||||
{
|
||||
iss >> iformat(buffer[0]) >> iformat(buffer[1]) >> iformat(buffer[2]);
|
||||
}
|
||||
|
||||
// tex coord
|
||||
if(has_texcoords)
|
||||
{
|
||||
iss >> iformat(buffer[0]) >> iformat(buffer[1]);
|
||||
texcoords[v] = Vector_3(buffer[0], buffer[1], 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// read faces: #N v[1] v[2] ... v[n-1]
|
||||
std::vector<typename Mesh::Vertex_index> vertices;
|
||||
for(i=0; i<nF; ++i)
|
||||
{
|
||||
// read line
|
||||
getline(in, line);
|
||||
if(line[0] == '#') // if the first column is a # we are looking at a comment line
|
||||
{
|
||||
--i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// #vertices
|
||||
std::istringstream iss(line);
|
||||
iss >> nV;
|
||||
vertices.resize(nV);
|
||||
|
||||
// indices
|
||||
for(j=0; j<nV; ++j)
|
||||
{
|
||||
iss >> idx;
|
||||
vertices[j] = typename Mesh::Vertex_index(idx);
|
||||
}
|
||||
|
||||
if(!mesh.add_face(vertices).is_valid()) {
|
||||
// adding a face did not succeed, stop reading the rest
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// @todo move that to read_polygon_mesh in BGL
|
||||
|
||||
/// \addtogroup PkgSurfaceMeshIO
|
||||
///
|
||||
|
|
@ -232,90 +48,6 @@ bool read_off_ascii(Surface_mesh<Point_3>& mesh,
|
|||
///
|
||||
/// @{
|
||||
|
||||
/// This function reads an `OFF` file into a `Surface_mesh`. It
|
||||
/// supports the `OFF` vertex properties normal, color, and vertex
|
||||
/// coordinates. If a property is detected in the `OFF` file, it will be
|
||||
/// read into the `mesh` as a vertex property with the name
|
||||
/// `"v:normal"`, `"v:color"`, and `"v:texcoord"`, respectivly.
|
||||
///
|
||||
/// @param mesh The mesh that should contain the file contents.
|
||||
/// @param filename The name of the file to be read.
|
||||
///
|
||||
/// @returns `true`, if reading succeeded, `false` otherwise
|
||||
///
|
||||
template <typename K>
|
||||
bool read_off(Surface_mesh<K>& mesh, const std::string& filename)
|
||||
{
|
||||
std::string line;
|
||||
bool has_texcoords = false;
|
||||
bool has_normals = false;
|
||||
bool has_hcoords = false;
|
||||
bool has_dim = false;
|
||||
bool is_binary = false;
|
||||
|
||||
// open file (in ASCII mode)
|
||||
std::ifstream in(filename.c_str());
|
||||
if(!in) return false;
|
||||
|
||||
// read header: [ST][C][N][4][n]OFF BINARY
|
||||
std::getline(in,line);
|
||||
const char *c = line.c_str();
|
||||
if(c[0] == 'S' && c[1] == 'T') { has_texcoords = true; c += 2; }
|
||||
if(c[0] == 'N') { has_normals = true; ++c; }
|
||||
if(c[0] == '4') { has_hcoords = true; ++c; }
|
||||
if(c[0] == 'n') { has_dim = true; ++c; }
|
||||
if(strncmp(c, "OFF", 3) != 0) { in.close(); return false; } // no OFF
|
||||
if(strncmp(c+4, "BINARY", 6) == 0) is_binary = true;
|
||||
|
||||
|
||||
// homogeneous coords, and vertex dimension != 3 are not supported
|
||||
if(has_hcoords || has_dim)
|
||||
{
|
||||
in.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// if binary: reopen file in binary mode
|
||||
if(is_binary)
|
||||
{
|
||||
in.close();
|
||||
in.open(filename.c_str(), std::ios::binary);
|
||||
std::getline(in,line);
|
||||
}
|
||||
|
||||
// read as ASCII or binary
|
||||
bool ok = (is_binary ?
|
||||
internal::read_off_binary(mesh, in, has_normals, has_texcoords) :
|
||||
internal::read_off_ascii(mesh, in, has_normals, has_texcoords));
|
||||
|
||||
in.close();
|
||||
return ok;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/// This function writes a `Surface_mesh` into an ASCII `OFF`
|
||||
/// file. It does not support properties.
|
||||
///
|
||||
/// @param mesh The mesh that should be written.
|
||||
/// @param filename The name of the file to be written.
|
||||
///
|
||||
/// @returns `true`, if reading succeeded, `false` otherwise
|
||||
///
|
||||
#endif
|
||||
template <typename K>
|
||||
bool write_off(const Surface_mesh<K>& mesh, const std::string& filename)
|
||||
{
|
||||
std::ofstream out(filename.c_str());
|
||||
if(out.fail())
|
||||
return false;
|
||||
|
||||
out << std::setprecision(17);
|
||||
write_off(out, mesh);
|
||||
|
||||
return !out.fail();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/// Read a file into a `Surface_mesh`. The extension of the
|
||||
/// filename determines which reader is used.
|
||||
|
|
@ -330,7 +62,8 @@ bool write_off(const Surface_mesh<K>& mesh, const std::string& filename)
|
|||
///
|
||||
#endif
|
||||
template <typename K>
|
||||
bool read_mesh(Surface_mesh<K>& mesh, const std::string& filename) {
|
||||
bool read_mesh(Surface_mesh<K>& mesh, const std::string& filename)
|
||||
{
|
||||
// clear mesh before reading from file
|
||||
mesh.clear();
|
||||
|
||||
|
|
@ -382,6 +115,8 @@ bool write_mesh(const Surface_mesh<K>& mesh, const std::string& filename)
|
|||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_IO_H
|
||||
|
|
|
|||
|
|
@ -13,13 +13,18 @@
|
|||
#ifndef CGAL_SURFACE_MESH_IO_3MF_H
|
||||
#define CGAL_SURFACE_MESH_IO_3MF_H
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_3MF
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/IO/3MF.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
namespace CGAL{
|
||||
/*!
|
||||
* Extracts the surface meshes from an input 3mf file and appends it to `output`.
|
||||
*\tparam Point the Point type of the output meshes.
|
||||
|
|
@ -27,7 +32,6 @@ namespace CGAL{
|
|||
* \param output a `std::vector` containing the `CGAL::Surface_mesh`s that will be filled by this function.
|
||||
* \return the number of extracted meshes.
|
||||
*/
|
||||
|
||||
template<typename Point>
|
||||
int read_3mf(const std::string& file_name,
|
||||
std::vector<CGAL::Surface_mesh<Point> >& output)
|
||||
|
|
@ -44,38 +48,36 @@ int read_3mf(const std::string& file_name,
|
|||
std::vector<std::string> names;
|
||||
std::vector<std::vector<CGAL::Color> > all_colors;
|
||||
int result = 0;
|
||||
int nb_meshes =
|
||||
CGAL::read_triangle_soups_from_3mf(file_name,
|
||||
all_points, all_polygons, all_colors, names);
|
||||
if(nb_meshes < 0 )
|
||||
|
||||
int nb_meshes = CGAL::read_triangle_soups_from_3mf(file_name, all_points, all_polygons, all_colors, names);
|
||||
if(nb_meshes < 0)
|
||||
{
|
||||
std::cerr << "Error in reading meshes."<<std::endl;
|
||||
std::cerr << "Error in reading meshes." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
output.reserve(nb_meshes);
|
||||
for(int i = 0; i< nb_meshes; ++i)
|
||||
for(int i=0; i<nb_meshes; ++i)
|
||||
{
|
||||
bool skip = false;
|
||||
SMesh sm;
|
||||
PolygonRange triangles = all_polygons[i];
|
||||
PointRange points = all_points[i];
|
||||
std::vector<CGAL::Color> colors = all_colors[i];
|
||||
//Create the surface mesh from scratch
|
||||
|
||||
// Create the surface mesh from scratch
|
||||
std::size_t n(points.size());
|
||||
sm.reserve(n,0, triangles.size());
|
||||
sm.reserve(n, 0, triangles.size());
|
||||
for(const Point& p : points)
|
||||
{
|
||||
sm.add_vertex(p);
|
||||
}
|
||||
|
||||
for(Polygon& triangle : triangles)
|
||||
{
|
||||
std::vector<Vertex_index> face;
|
||||
face.reserve(triangle.size());
|
||||
for(auto index : triangle)
|
||||
{
|
||||
for(std::size_t index : triangle)
|
||||
face.push_back(Vertex_index(index));
|
||||
}
|
||||
|
||||
Face_index fi = sm.add_face(face);
|
||||
if(fi == sm.null_face())
|
||||
{
|
||||
|
|
@ -84,34 +86,39 @@ int read_3mf(const std::string& file_name,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(skip)
|
||||
continue;
|
||||
//end constructin the surface mesh from scratch
|
||||
|
||||
CGAL::Color first = colors.front();
|
||||
const Color& first = colors.front();
|
||||
bool need_pmap = false;
|
||||
for(auto color : colors)
|
||||
for(const Color& color : colors)
|
||||
{
|
||||
if (color != first)
|
||||
if(color != first)
|
||||
{
|
||||
need_pmap = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(need_pmap)
|
||||
{
|
||||
typename SMesh::template Property_map<Face_index, CGAL::Color> fcolor =
|
||||
sm.template add_property_map<Face_index,CGAL::Color>("f:color",first).first;
|
||||
for(std::size_t pid = 0; pid < colors.size(); ++pid)
|
||||
{
|
||||
put(fcolor, Face_index(pid), colors[pid]);//should work bc mesh is just created and shouldn't have any destroyed face.
|
||||
}
|
||||
sm.template add_property_map<Face_index,CGAL::Color>("f:color", first).first;
|
||||
|
||||
for(std::size_t pid=0, cs=colors.size(); pid<cs; ++pid)
|
||||
put(fcolor, Face_index(pid), colors[pid]); // there can't have any deleted face yet
|
||||
}
|
||||
|
||||
output.push_back(sm);
|
||||
++result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}//end CGAL
|
||||
#endif // CGAL_SURFACE_MESH_3MF_H
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_LINKED_WITH_3MF
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_IO_3MF_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,202 @@
|
|||
// Copyright (c) 2018 GeometryFactory Sarl (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_IO_OFF_H
|
||||
#define CGAL_SURFACE_MESH_IO_OFF_H
|
||||
|
||||
#include <CGAL/license/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Surface_mesh/Surface_mesh_fwd.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
#include <CGAL/boost/graph/Named_function_parameters.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
|
||||
#include <CGAL/IO/Color.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <tuple>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Read
|
||||
|
||||
/// \relates Surface_mesh
|
||||
///
|
||||
/// Extracts the surface mesh from an input stream in Ascii OFF, COFF, NOFF, CNOFF
|
||||
/// format and appends it to the surface mesh `sm`.
|
||||
///
|
||||
/// The operator reads the point property as well as "v:normal", "v:color", `"v:texcoord"`, and "f:color".
|
||||
/// If an alternative vertex_point map is given through `np`,
|
||||
/// then it will be used instead of the default one.
|
||||
///
|
||||
/// \pre The data in the stream must represent a two-manifold. If this is not the case
|
||||
/// the `failbit` of `is` is set and the mesh cleared.
|
||||
///
|
||||
template <typename Point, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool read_OFF(std::istream& is,
|
||||
Surface_mesh<Point>& sm,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
typedef Surface_mesh<Point> Mesh;
|
||||
typedef typename Mesh::Vertex_index Vertex_index;
|
||||
typedef typename Mesh::Face_index Face_index;
|
||||
|
||||
typedef typename Kernel_traits<Point>::Kernel K;
|
||||
typedef typename K::Vector_3 Normal;
|
||||
typedef typename K::Point_2 Texture;
|
||||
typedef CGAL::Color Color;
|
||||
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
|
||||
typename CGAL::GetVertexPointMap<Mesh, CGAL_BGL_NP_CLASS>::type
|
||||
vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_property_map(CGAL::vertex_point, sm));
|
||||
|
||||
typename Mesh::template Property_map<Vertex_index, Normal> vnormals;
|
||||
typename Mesh::template Property_map<Vertex_index, Texture> vtextures;
|
||||
typename Mesh::template Property_map<Vertex_index, Color> vcolors;
|
||||
typename Mesh::template Property_map<Face_index, Color> fcolors;
|
||||
bool created;
|
||||
|
||||
std::tie(vnormals, created) = sm.template add_property_map<Vertex_index, Normal>("v:normal");
|
||||
CGAL_assertion(created);
|
||||
std::tie(vcolors, created) = sm.template add_property_map<Vertex_index, Color>("v:color", Color(0,0,0));
|
||||
CGAL_assertion(created);
|
||||
std::tie(vtextures, created) = sm.template add_property_map<Vertex_index, Texture>("v:texcoord");
|
||||
CGAL_assertion(created);
|
||||
std::tie(fcolors, created) = sm.template add_property_map<Face_index, Color>("f:color", Color(0,0,0));
|
||||
CGAL_assertion(created);
|
||||
|
||||
return IO::internal::read_OFF_BGL(is, sm, CGAL::parameters::vertex_point_map(vpm)
|
||||
.vertex_normal_map(vnormals)
|
||||
.vertex_color_map(vcolors)
|
||||
.vertex_texture_map(vtextures)
|
||||
.face_color_map(fcolors));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Write
|
||||
|
||||
namespace IO {
|
||||
namespace internal {
|
||||
|
||||
template <typename Point, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF_with_or_without_fcolors(std::ostream& os,
|
||||
const Surface_mesh<Point>& sm,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
typedef Surface_mesh<Point> Mesh;
|
||||
typedef typename Mesh::Face_index Face_index;
|
||||
typedef CGAL::Color Color;
|
||||
|
||||
typename Mesh::template Property_map<Face_index, Color> fcolors;
|
||||
bool has_fcolors;
|
||||
std::tie(fcolors, has_fcolors) = sm.template property_map<Face_index, CGAL::Color>("f:color");
|
||||
|
||||
if(has_fcolors)
|
||||
return write_OFF_BGL(os, sm, np.face_color_map(fcolors));
|
||||
else
|
||||
return write_OFF_BGL(os, sm, np);
|
||||
}
|
||||
|
||||
template <typename Point, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF_with_or_without_vtextures(std::ostream& os,
|
||||
const Surface_mesh<Point>& sm,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
typedef Surface_mesh<Point> Mesh;
|
||||
typedef typename Mesh::Vertex_index Vertex_index;
|
||||
|
||||
typedef typename Kernel_traits<Point>::Kernel K;
|
||||
typedef typename K::Point_2 Texture;
|
||||
|
||||
typename Mesh::template Property_map<Vertex_index, Texture> vtextures;
|
||||
bool has_vtextures;
|
||||
std::tie(vtextures, has_vtextures) = sm.template property_map<Vertex_index, Texture>("v:texcoord");
|
||||
|
||||
if(has_vtextures)
|
||||
return write_OFF_with_or_without_fcolors(os, sm, np.vertex_texture_map(vtextures));
|
||||
else
|
||||
return write_OFF_with_or_without_fcolors(os, sm, np);
|
||||
}
|
||||
|
||||
template <typename Point, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF_with_or_without_vcolors(std::ostream& os,
|
||||
const Surface_mesh<Point>& sm,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
typedef Surface_mesh<Point> Mesh;
|
||||
typedef typename Mesh::Vertex_index Vertex_index;
|
||||
typedef CGAL::Color Color;
|
||||
|
||||
typename Mesh::template Property_map<Vertex_index, Color> vcolors;
|
||||
bool has_vcolors;
|
||||
std::tie(vcolors, has_vcolors) = sm.template property_map<Vertex_index, CGAL::Color>("v:color");
|
||||
|
||||
if(has_vcolors)
|
||||
return write_OFF_with_or_without_vtextures(os, sm, np.vertex_color_map(vcolors));
|
||||
else
|
||||
return write_OFF_with_or_without_vtextures(os, sm, np);
|
||||
}
|
||||
|
||||
template <typename Point, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF_with_or_without_vnormals(std::ostream& os,
|
||||
const Surface_mesh<Point>& sm,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
typedef Surface_mesh<Point> Mesh;
|
||||
typedef typename Mesh::Vertex_index Vertex_index;
|
||||
|
||||
typedef typename Kernel_traits<Point>::Kernel K;
|
||||
typedef typename K::Vector_3 Normal;
|
||||
|
||||
typename Mesh::template Property_map<Vertex_index, Normal> vnormals;
|
||||
bool has_vnormals;
|
||||
std::tie(vnormals, has_vnormals) = sm.template property_map<Vertex_index, Normal>("v:normal");
|
||||
|
||||
if(has_vnormals)
|
||||
return write_OFF_with_or_without_vcolors(os, sm, np.vertex_normal_map(vnormals));
|
||||
else
|
||||
return write_OFF_with_or_without_vcolors(os, sm, np);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace IO
|
||||
|
||||
/// \relates Surface_mesh
|
||||
///
|
||||
/// Inserts the surface mesh in an output stream.
|
||||
///
|
||||
/// \note The <A HREF="https://en.cppreference.com/w/cpp/io/ios_base/precision" >`precision()`</A>
|
||||
/// of the output stream might not be sufficient depending on the data to be written.
|
||||
///
|
||||
template <typename Point, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
bool write_OFF(std::ostream& os,
|
||||
const Surface_mesh<Point>& sm,
|
||||
const CGAL_BGL_NP_CLASS& np)
|
||||
{
|
||||
// Just to discard any excess named parameters
|
||||
typename CGAL::GetVertexPointMap<Surface_mesh<Point>, CGAL_BGL_NP_CLASS>::const_type
|
||||
vpm = parameters::choose_parameter(parameters::get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(CGAL::vertex_point, sm));
|
||||
|
||||
return IO::internal::write_OFF_with_or_without_vnormals(os, sm, parameters::vertex_point_map(vpm));
|
||||
}
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_IO_OFF_H
|
||||
|
|
@ -13,14 +13,14 @@
|
|||
#ifndef CGAL_SURFACE_MESH_IO_PLY
|
||||
#define CGAL_SURFACE_MESH_IO_PLY
|
||||
|
||||
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
||||
|
||||
#include <CGAL/IO/PLY.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace IO {
|
||||
namespace internal {
|
||||
|
||||
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
||||
|
||||
template <typename Point>
|
||||
class Surface_mesh_filler
|
||||
{
|
||||
|
|
@ -695,10 +695,331 @@ void fill_header(std::ostream& os, const Surface_mesh<Point>& sm,
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace IO
|
||||
|
||||
/// \relates Surface_mesh
|
||||
/// Inserts the surface mesh in an output stream in PLY format.
|
||||
/// If found, "v:normal", "v:color" and "f:color" are inserted in the stream.
|
||||
/// All other vertex and face properties with simple types are inserted in the stream.
|
||||
/// Edges are only inserted in the stream if they have at least one
|
||||
/// property with simple type: if they do, all edge properties with
|
||||
/// simple types are inserted in the stream. The halfedges follow
|
||||
/// the same behavior.
|
||||
///
|
||||
/// If provided, the `comments` string is included line by line in
|
||||
/// the header of the PLY stream (each line will be precedeed by
|
||||
/// "comment ").
|
||||
///
|
||||
template <typename P>
|
||||
bool read_PLY(std::ostream& os, const Surface_mesh<P>& sm, const std::string& comments = std::string())
|
||||
{
|
||||
typedef Surface_mesh<P> SMesh;
|
||||
typedef typename SMesh::Vertex_index VIndex;
|
||||
typedef typename SMesh::Face_index FIndex;
|
||||
typedef typename SMesh::Edge_index EIndex;
|
||||
typedef typename SMesh::Halfedge_index HIndex;
|
||||
|
||||
os << "ply" << std::endl
|
||||
<<((get_mode(os) == IO::BINARY) ? "format binary_little_endian 1.0" : "format ascii 1.0") << std::endl
|
||||
<< "comment Generated by the CGAL library" << std::endl;
|
||||
|
||||
if(comments != std::string())
|
||||
{
|
||||
std::istringstream iss(comments);
|
||||
std::string line;
|
||||
while(getline(iss, line))
|
||||
{
|
||||
if(line != "Generated by the CGAL library") // Avoid repeating the line if multiple savings
|
||||
os << "comment " << line << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
os << "element vertex " << sm.number_of_vertices() << std::endl;
|
||||
|
||||
std::vector<IO::internal::Abstract_property_printer<VIndex>*> vprinters;
|
||||
IO::internal::fill_header(os, sm, vprinters);
|
||||
|
||||
os << "element face " << sm.number_of_faces() << std::endl;
|
||||
os << "property list uchar int vertex_indices" << std::endl;
|
||||
std::vector<IO::internal::Abstract_property_printer<FIndex>*> fprinters;
|
||||
IO::internal::fill_header(os, sm, fprinters);
|
||||
|
||||
|
||||
std::vector<IO::internal::Abstract_property_printer<EIndex>*> eprinters;
|
||||
if(sm.template properties<EIndex>().size() > 1)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
IO::internal::fill_header(oss, sm, eprinters);
|
||||
|
||||
if(!eprinters.empty())
|
||||
{
|
||||
os << "element edge " << sm.number_of_edges() << std::endl;
|
||||
os << "property int v0" << std::endl;
|
||||
os << "property int v1" << std::endl;
|
||||
os << oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<IO::internal::Abstract_property_printer<HIndex>*> hprinters;
|
||||
if(sm.template properties<HIndex>().size() > 1)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
IO::internal::fill_header(oss, sm, hprinters);
|
||||
|
||||
if(!hprinters.empty())
|
||||
{
|
||||
os << "element halfedge " << sm.number_of_halfedges() << std::endl;
|
||||
os << "property int source" << std::endl;
|
||||
os << "property int target" << std::endl;
|
||||
os << oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
os << "end_header" << std::endl;
|
||||
|
||||
for(VIndex vi : sm.vertices())
|
||||
{
|
||||
for(std::size_t i = 0; i < vprinters.size(); ++ i)
|
||||
{
|
||||
vprinters[i]->print(os, vi);
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
std::vector<VIndex> polygon;
|
||||
|
||||
for(FIndex fi : sm.faces())
|
||||
{
|
||||
// Get list of vertex indices
|
||||
polygon.clear();
|
||||
for(HIndex hi : halfedges_around_face(halfedge(fi, sm), sm))
|
||||
polygon.push_back(sm.target(hi));
|
||||
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
{
|
||||
os << polygon.size() << " ";
|
||||
for(std::size_t i = 0; i < polygon.size(); ++ i)
|
||||
os << int(polygon[i]) << " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char size =(unsigned char)(polygon.size());
|
||||
os.write(reinterpret_cast<char*>(&size), sizeof(size));
|
||||
for(std::size_t i = 0; i < polygon.size(); ++ i)
|
||||
{
|
||||
int idx = int(polygon[i]);
|
||||
os.write(reinterpret_cast<char*>(&idx), sizeof(idx));
|
||||
}
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < fprinters.size(); ++ i)
|
||||
{
|
||||
fprinters[i]->print(os, fi);
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
if(!eprinters.empty())
|
||||
{
|
||||
for(EIndex ei : sm.edges())
|
||||
{
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << int(sm.vertex(ei,0)) << " " << int(sm.vertex(ei,1)) << " ";
|
||||
else
|
||||
{
|
||||
int v0 = int(sm.vertex(ei,0));
|
||||
int v1 = int(sm.vertex(ei,1));
|
||||
os.write(reinterpret_cast<char*>(&v0), sizeof(v0));
|
||||
os.write(reinterpret_cast<char*>(&v1), sizeof(v1));
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < eprinters.size(); ++ i)
|
||||
{
|
||||
eprinters[i]->print(os, ei);
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if(!hprinters.empty())
|
||||
{
|
||||
for(HIndex hi : sm.halfedges())
|
||||
{
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << int(sm.source(hi)) << " " << int(sm.target(hi)) << " ";
|
||||
else
|
||||
{
|
||||
int source = int(sm.source(hi));
|
||||
int target = int(sm.target(hi));
|
||||
os.write(reinterpret_cast<char*>(&source), sizeof(source));
|
||||
os.write(reinterpret_cast<char*>(&target), sizeof(target));
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < hprinters.size(); ++ i)
|
||||
{
|
||||
hprinters[i]->print(os, hi);
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
|
||||
if(get_mode(os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < vprinters.size(); ++ i)
|
||||
delete vprinters[i];
|
||||
for(std::size_t i = 0; i < fprinters.size(); ++ i)
|
||||
delete fprinters[i];
|
||||
for(std::size_t i = 0; i < eprinters.size(); ++ i)
|
||||
delete eprinters[i];
|
||||
for(std::size_t i = 0; i < hprinters.size(); ++ i)
|
||||
delete hprinters[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <typename P>
|
||||
bool read_PLY(std::istream& is, Surface_mesh<P>& sm)
|
||||
{
|
||||
std::string dummy;
|
||||
return read_PLY(is, sm, dummy);
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/// Extracts the surface mesh from an input stream in Ascii or
|
||||
/// Binary PLY format and appends it to the surface mesh `sm`.
|
||||
///
|
||||
/// - the operator reads the vertex `point` property and the face
|
||||
/// `vertex_index` (or `vertex_indices`) property;
|
||||
/// - if three PLY properties `nx`, `ny` and `nz` with type `float`
|
||||
/// or `double` are found for vertices, a "v:normal" vertex
|
||||
/// property map is added;
|
||||
/// - if three PLY properties `red`, `green` and `blue` with type
|
||||
/// `uchar` are found for vertices, a "v:color" vertex property
|
||||
/// map is added;
|
||||
/// - if three PLY properties `red`, `green` and `blue` with type
|
||||
/// `uchar` are found for faces, a "f:color" face property map is
|
||||
/// added;
|
||||
/// - if any other PLY property is found, a "[s]:[name]" property map is
|
||||
/// added, where `[s]` is `v` for vertex and `f` for face, and
|
||||
/// `[name]` is the name of the PLY property.
|
||||
///
|
||||
/// The `comments` parameter can be omitted. If provided, it will be
|
||||
/// used to store the potential comments found in the PLY
|
||||
/// header. Each line starting by "comment " in the header is
|
||||
/// appended to the `comments` string (without the "comment " word).
|
||||
///
|
||||
/// \pre The data in the stream must represent a two-manifold. If this is not the case
|
||||
/// the `failbit` of `is` is set and the mesh cleared.
|
||||
/// \relates Surface_mesh
|
||||
|
||||
template <typename P>
|
||||
bool read_PLY(std::istream& is,
|
||||
Surface_mesh<P>& sm,
|
||||
std::string& comments)
|
||||
{
|
||||
typedef typename Surface_mesh<P>::size_type size_type;
|
||||
|
||||
if(!is.good())
|
||||
{
|
||||
std::cerr << "Error: cannot open file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
IO::internal::PLY_reader reader;
|
||||
IO::internal::Surface_mesh_filler<P> filler(sm);
|
||||
|
||||
if(!(reader.init(is)))
|
||||
{
|
||||
is.setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
comments = reader.comments();
|
||||
|
||||
for(std::size_t i = 0; i < reader.number_of_elements(); ++ i)
|
||||
{
|
||||
IO::internal::PLY_element& element = reader.element(i);
|
||||
|
||||
bool is_vertex =(element.name() == "vertex" || element.name() == "vertices");
|
||||
bool is_face = false;
|
||||
bool is_edge = false;
|
||||
bool is_halfedge = false;
|
||||
if(is_vertex)
|
||||
{
|
||||
sm.reserve(sm.number_of_vertices() + size_type(element.number_of_items()),
|
||||
sm.number_of_edges(),
|
||||
sm.number_of_faces());
|
||||
filler.instantiate_vertex_properties(element);
|
||||
}
|
||||
else
|
||||
is_face =(element.name() == "face" || element.name() == "faces");
|
||||
|
||||
if(is_face)
|
||||
{
|
||||
sm.reserve(sm.number_of_vertices(),
|
||||
sm.number_of_edges(),
|
||||
sm.number_of_faces() + size_type(element.number_of_items()));
|
||||
filler.instantiate_face_properties(element);
|
||||
}
|
||||
else
|
||||
is_edge =(element.name() == "edge");
|
||||
|
||||
if(is_edge)
|
||||
filler.instantiate_edge_properties(element);
|
||||
else
|
||||
is_halfedge =(element.name() == "halfedge");
|
||||
|
||||
if(is_halfedge)
|
||||
filler.instantiate_halfedge_properties(element);
|
||||
|
||||
for(std::size_t j = 0; j < element.number_of_items(); ++ j)
|
||||
{
|
||||
for(std::size_t k = 0; k < element.number_of_properties(); ++ k)
|
||||
{
|
||||
IO::internal::PLY_read_number* property = element.property(k);
|
||||
property->get(is);
|
||||
if(is.fail())
|
||||
return false;
|
||||
}
|
||||
|
||||
if(is_vertex)
|
||||
filler.process_vertex_line(element);
|
||||
else if(is_face)
|
||||
{
|
||||
if(!filler.process_face_line(element))
|
||||
{
|
||||
is.setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(is_edge)
|
||||
filler.process_edge_line(element);
|
||||
else if(is_halfedge)
|
||||
filler.process_halfedge_line(element);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
||||
|
||||
#endif // CGAL_SURFACE_MESH_IO_PLY
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
|
||||
|
||||
#ifndef CGAL_SURFACE_MESH_PROPERTY_H
|
||||
#define CGAL_SURFACE_MESH_PROPERTY_H
|
||||
|
||||
|
|
@ -18,13 +17,13 @@
|
|||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/property_map.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@
|
|||
|
||||
namespace CGAL {
|
||||
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
/// Base class for vertex, halfedge, edge, and face index.
|
||||
///
|
||||
|
|
@ -2126,577 +2125,23 @@ private: //------------------------------------------------------- private data
|
|||
return sm;
|
||||
}
|
||||
|
||||
|
||||
/// \relates Surface_mesh
|
||||
/// Inserts the surface mesh in an output stream in Ascii OFF format.
|
||||
/// Only the \em point property is inserted in the stream.
|
||||
/// If an alternative vertex_point map is given through `np`,
|
||||
/// then it will be used instead of the default one.
|
||||
/// \pre `operator<<(std::ostream&,const P&)` must be defined.
|
||||
/// \note The <A HREF="https://en.cppreference.com/w/cpp/io/ios_base/precision">`precision()`</A>
|
||||
/// of the output stream might not be sufficient depending on the data to be written.
|
||||
|
||||
template <typename P, typename NamedParameters>
|
||||
bool write_off(std::ostream& os, const Surface_mesh<P>& sm, const NamedParameters& np) {
|
||||
typedef Surface_mesh<P> Mesh;
|
||||
typedef typename Mesh::Vertex_index Vertex_index;
|
||||
typedef typename Mesh::Face_index Face_index;
|
||||
|
||||
typename Mesh::template Property_map<typename Mesh::Vertex_index, CGAL::Color> vcolors;
|
||||
bool has_vcolors;
|
||||
boost::tie(vcolors, has_vcolors) = sm.template property_map<typename Mesh::Vertex_index, CGAL::Color >("v:color");
|
||||
typename Mesh::template Property_map<typename Mesh::Face_index, CGAL::Color> fcolors;
|
||||
bool has_fcolors;
|
||||
boost::tie(fcolors, has_fcolors) = sm.template property_map<typename Mesh::Face_index, CGAL::Color >("f:color");
|
||||
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
|
||||
if(!has_fcolors && !has_vcolors)
|
||||
os << "OFF\n" << sm.number_of_vertices() << " " << sm.number_of_faces() << " 0\n";
|
||||
else
|
||||
os << "COFF\n" << sm.number_of_vertices() << " " << sm.number_of_faces() << " 0\n";
|
||||
std::vector<int> reindex;
|
||||
typename CGAL::GetVertexPointMap<Surface_mesh<P>, NamedParameters>::const_type
|
||||
vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(CGAL::vertex_point, sm));
|
||||
reindex.resize(sm.num_vertices());
|
||||
int n = 0;
|
||||
for(Vertex_index v : sm.vertices()){
|
||||
|
||||
P p = get(vpm, v);
|
||||
os << p.x() << " " << p.y() << " " << p.z();
|
||||
if(has_vcolors)
|
||||
{
|
||||
CGAL::Color color = vcolors[v];
|
||||
os <<" "<< static_cast<int>(color.r())<<" "<< static_cast<int>(color.g())<<" "<< static_cast<int>(color.b());
|
||||
}
|
||||
os << '\n';
|
||||
reindex[v]=n++;
|
||||
}
|
||||
|
||||
for(Face_index f : sm.faces()){
|
||||
os << sm.degree(f);
|
||||
for(Vertex_index v : CGAL::vertices_around_face(sm.halfedge(f),sm)){
|
||||
os << " " << reindex[v];
|
||||
}
|
||||
if(has_fcolors)
|
||||
{
|
||||
CGAL::Color color = fcolors[f];
|
||||
os <<" "<< static_cast<int>(color.r())<<" "<< static_cast<int>(color.g())<<" "<< static_cast<int>(color.b());
|
||||
}
|
||||
os << '\n';
|
||||
}
|
||||
return os.good();
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
bool write_off(std::ostream& os, const Surface_mesh<P>& sm) {
|
||||
return write_off(os, sm, CGAL::parameters::all_default());
|
||||
}
|
||||
/// \relates Surface_mesh
|
||||
///
|
||||
/// This operator calls `write_off(std::ostream& os, const CGAL::Surface_mesh& sm)`.
|
||||
/// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`.
|
||||
template <typename P>
|
||||
std::ostream& operator<<(std::ostream& os, const Surface_mesh<P>& sm)
|
||||
{
|
||||
write_off(os, sm, CGAL::parameters::all_default());
|
||||
write_OFF(os, sm);
|
||||
return os;
|
||||
}
|
||||
|
||||
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
||||
|
||||
/// \relates Surface_mesh
|
||||
/// Inserts the surface mesh in an output stream in PLY format.
|
||||
/// If found, "v:normal", "v:color" and "f:color" are inserted in the stream.
|
||||
/// All other vertex and face properties with simple types are inserted in the stream.
|
||||
/// Edges are only inserted in the stream if they have at least one
|
||||
/// property with simple type: if they do, all edge properties with
|
||||
/// simple types are inserted in the stream. The halfedges follow
|
||||
/// the same behavior.
|
||||
///
|
||||
/// If provided, the `comments` string is included line by line in
|
||||
/// the header of the PLY stream (each line will be precedeed by
|
||||
/// "comment ").
|
||||
///
|
||||
template <typename P>
|
||||
bool write_ply(std::ostream& os, const Surface_mesh<P>& sm, const std::string& comments = std::string())
|
||||
{
|
||||
typedef Surface_mesh<P> SMesh;
|
||||
typedef typename SMesh::Vertex_index VIndex;
|
||||
typedef typename SMesh::Face_index FIndex;
|
||||
typedef typename SMesh::Edge_index EIndex;
|
||||
typedef typename SMesh::Halfedge_index HIndex;
|
||||
|
||||
os << "ply" << std::endl
|
||||
<< ((get_mode(os) == IO::BINARY) ? "format binary_little_endian 1.0" : "format ascii 1.0") << std::endl
|
||||
<< "comment Generated by the CGAL library" << std::endl;
|
||||
|
||||
if (comments != std::string())
|
||||
{
|
||||
std::istringstream iss (comments);
|
||||
std::string line;
|
||||
while (getline(iss, line))
|
||||
{
|
||||
if (line != "Generated by the CGAL library") // Avoid repeating the line if multiple savings
|
||||
os << "comment " << line << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
os << "element vertex " << sm.number_of_vertices() << std::endl;
|
||||
|
||||
std::vector<IO::internal::Abstract_property_printer<VIndex>*> vprinters;
|
||||
IO::internal::fill_header (os, sm, vprinters);
|
||||
|
||||
os << "element face " << sm.number_of_faces() << std::endl;
|
||||
os << "property list uchar int vertex_indices" << std::endl;
|
||||
std::vector<IO::internal::Abstract_property_printer<FIndex>*> fprinters;
|
||||
IO::internal::fill_header (os, sm, fprinters);
|
||||
|
||||
|
||||
std::vector<IO::internal::Abstract_property_printer<EIndex>*> eprinters;
|
||||
if (sm.template properties<EIndex>().size() > 1)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
IO::internal::fill_header (oss, sm, eprinters);
|
||||
|
||||
if (!eprinters.empty())
|
||||
{
|
||||
os << "element edge " << sm.number_of_edges() << std::endl;
|
||||
os << "property int v0" << std::endl;
|
||||
os << "property int v1" << std::endl;
|
||||
os << oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<IO::internal::Abstract_property_printer<HIndex>*> hprinters;
|
||||
if (sm.template properties<HIndex>().size() > 1)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
IO::internal::fill_header (oss, sm, hprinters);
|
||||
|
||||
if (!hprinters.empty())
|
||||
{
|
||||
os << "element halfedge " << sm.number_of_halfedges() << std::endl;
|
||||
os << "property int source" << std::endl;
|
||||
os << "property int target" << std::endl;
|
||||
os << oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
os << "end_header" << std::endl;
|
||||
|
||||
for(VIndex vi : sm.vertices())
|
||||
{
|
||||
for (std::size_t i = 0; i < vprinters.size(); ++ i)
|
||||
{
|
||||
vprinters[i]->print(os, vi);
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
std::vector<VIndex> polygon;
|
||||
|
||||
for(FIndex fi : sm.faces())
|
||||
{
|
||||
// Get list of vertex indices
|
||||
polygon.clear();
|
||||
for(HIndex hi : halfedges_around_face(halfedge(fi, sm), sm))
|
||||
polygon.push_back (sm.target(hi));
|
||||
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
{
|
||||
os << polygon.size() << " ";
|
||||
for (std::size_t i = 0; i < polygon.size(); ++ i)
|
||||
os << int(polygon[i]) << " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char size = (unsigned char)(polygon.size());
|
||||
os.write (reinterpret_cast<char*>(&size), sizeof(size));
|
||||
for (std::size_t i = 0; i < polygon.size(); ++ i)
|
||||
{
|
||||
int idx = int(polygon[i]);
|
||||
os.write (reinterpret_cast<char*>(&idx), sizeof(idx));
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < fprinters.size(); ++ i)
|
||||
{
|
||||
fprinters[i]->print(os, fi);
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
if (!eprinters.empty())
|
||||
{
|
||||
for(EIndex ei : sm.edges())
|
||||
{
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << int(sm.vertex(ei,0)) << " " << int(sm.vertex(ei,1)) << " ";
|
||||
else
|
||||
{
|
||||
int v0 = int(sm.vertex(ei,0));
|
||||
int v1 = int(sm.vertex(ei,1));
|
||||
os.write (reinterpret_cast<char*>(&v0), sizeof(v0));
|
||||
os.write (reinterpret_cast<char*>(&v1), sizeof(v1));
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < eprinters.size(); ++ i)
|
||||
{
|
||||
eprinters[i]->print(os, ei);
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hprinters.empty())
|
||||
{
|
||||
for(HIndex hi : sm.halfedges())
|
||||
{
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << int(sm.source(hi)) << " " << int(sm.target(hi)) << " ";
|
||||
else
|
||||
{
|
||||
int source = int(sm.source(hi));
|
||||
int target = int(sm.target(hi));
|
||||
os.write (reinterpret_cast<char*>(&source), sizeof(source));
|
||||
os.write (reinterpret_cast<char*>(&target), sizeof(target));
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < hprinters.size(); ++ i)
|
||||
{
|
||||
hprinters[i]->print(os, hi);
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << " ";
|
||||
}
|
||||
|
||||
if (get_mode (os) == IO::ASCII)
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < vprinters.size(); ++ i)
|
||||
delete vprinters[i];
|
||||
for (std::size_t i = 0; i < fprinters.size(); ++ i)
|
||||
delete fprinters[i];
|
||||
for (std::size_t i = 0; i < eprinters.size(); ++ i)
|
||||
delete eprinters[i];
|
||||
for (std::size_t i = 0; i < hprinters.size(); ++ i)
|
||||
delete hprinters[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @cond CGAL_DOCUMENT_INTERNALS
|
||||
|
||||
inline std::istream& sm_skip_comments( std::istream& in) {
|
||||
char c;
|
||||
in >> c;
|
||||
while(c == '#')
|
||||
{
|
||||
in.ignore((std::numeric_limits<std::streamsize>::max)(), '\n');
|
||||
in >> c;
|
||||
}
|
||||
in.putback(c);
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @endcond
|
||||
|
||||
/// \relates Surface_mesh
|
||||
/// Extracts the surface mesh from an input stream in Ascii OFF, COFF, NOFF, CNOFF
|
||||
/// format and appends it to the surface mesh `sm`.
|
||||
/// The operator reads the point property as well as "v:normal", "v:color", and "f:color".
|
||||
/// Vertex texture coordinates are ignored.
|
||||
/// If an alternative vertex_point map is given through `np`,
|
||||
/// then it will be used instead of the default one.
|
||||
/// \pre `operator>>(std::istream&,const P&)` must be defined.
|
||||
/// \pre The data in the stream must represent a two-manifold. If this is not the case
|
||||
/// the `failbit` of `is` is set and the mesh cleared.
|
||||
|
||||
template <typename P, typename NamedParameters>
|
||||
bool read_off(std::istream& is, Surface_mesh<P>& sm, const NamedParameters& np)
|
||||
{
|
||||
typedef Surface_mesh<P> Mesh;
|
||||
typedef typename Kernel_traits<P>::Kernel K;
|
||||
typedef typename K::Vector_3 Vector_3;
|
||||
typedef typename Mesh::Face_index Face_index;
|
||||
typedef typename Mesh::Vertex_index Vertex_index;
|
||||
typedef typename Mesh::size_type size_type;
|
||||
using parameters::choose_parameter;
|
||||
using parameters::get_parameter;
|
||||
|
||||
typename CGAL::GetVertexPointMap<Surface_mesh<P>, NamedParameters>::type
|
||||
vpm = choose_parameter(get_parameter(np, CGAL::internal_np::vertex_point),
|
||||
get_property_map(CGAL::vertex_point, sm));
|
||||
int n, f, e;
|
||||
std::string off;
|
||||
is >> sm_skip_comments;
|
||||
is >> off;
|
||||
if(! (
|
||||
(off == "OFF") || (off == "COFF") || (off == "NOFF") || (off == "CNOFF")
|
||||
)
|
||||
)
|
||||
{
|
||||
is.setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
is >> n >> f >> e;
|
||||
if(!is){
|
||||
return false;
|
||||
}
|
||||
sm.reserve(sm.num_vertices()+n, sm.num_edges()+e, sm.num_faces()+f);
|
||||
std::vector<Vertex_index> vertexmap(n);
|
||||
|
||||
Vector_3 v;
|
||||
typename Mesh::template Property_map<Vertex_index,CGAL::Color> vcolor;
|
||||
typename Mesh::template Property_map<Vertex_index,Vector_3> vnormal;
|
||||
bool vcolored = false, v_has_normals = false;
|
||||
|
||||
if((off == "NOFF") || (off == "CNOFF")){
|
||||
bool created;
|
||||
boost::tie(vnormal, created) = sm.template add_property_map<Vertex_index,Vector_3>("v:normal",Vector_3(0,0,0));
|
||||
v_has_normals = true;
|
||||
}
|
||||
char ci;
|
||||
|
||||
for(int i=0; i < n; i++){
|
||||
is >> sm_skip_comments;
|
||||
double x, y, z;
|
||||
is >> iformat(x) >> iformat(y) >> iformat(z);
|
||||
|
||||
Vertex_index vi = sm.add_vertex();
|
||||
put(vpm, vi, P(x, y, z));
|
||||
|
||||
|
||||
vertexmap[i] = vi;
|
||||
if(v_has_normals){
|
||||
is >> v;
|
||||
vnormal[vi] = v;
|
||||
}
|
||||
|
||||
|
||||
if(i == 0 && ((off == "COFF") || (off == "CNOFF"))){
|
||||
std::string col;
|
||||
std::getline(is, col);
|
||||
std::istringstream iss(col);
|
||||
if(iss >> ci){
|
||||
bool created;
|
||||
boost::tie(vcolor, created) = sm.template add_property_map<Vertex_index,CGAL::Color>("v:color",CGAL::Color(0,0,0));
|
||||
std::istringstream iss2(col);
|
||||
vcolor[vi] = File_scanner_OFF::get_color_from_line(iss2);
|
||||
vcolored = true;
|
||||
}
|
||||
}else{
|
||||
if(vcolored){
|
||||
//stores the RGB value
|
||||
vcolor[vi] = File_scanner_OFF::get_color_from_line(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<Vertex_index> vr;
|
||||
size_type d, vi;
|
||||
bool fcolored = false;
|
||||
typename Mesh::template Property_map<Face_index,CGAL::Color> fcolor;
|
||||
|
||||
for(int i=0; i < f; i++){
|
||||
is >> sm_skip_comments;
|
||||
is >> d;
|
||||
if(!is){
|
||||
sm.clear();
|
||||
return false;
|
||||
}
|
||||
vr.resize(d);
|
||||
for(std::size_t j=0; j<d; j++){
|
||||
is >> vi;
|
||||
vr[j] = vertexmap[vi];
|
||||
}
|
||||
Face_index fi = sm.add_face(vr);
|
||||
if(fi == sm.null_face())
|
||||
{
|
||||
is.setstate(std::ios::failbit);
|
||||
sm.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// the first face will tell us if faces have a color map
|
||||
// TODO: extend this to RGBA
|
||||
if(i == 0 ){
|
||||
std::string col;
|
||||
std::getline(is, col);
|
||||
std::istringstream iss(col);
|
||||
if(iss >> ci){
|
||||
bool created;
|
||||
boost::tie(fcolor, created) = sm.template add_property_map<Face_index,CGAL::Color>("f:color",CGAL::Color(0,0,0));
|
||||
fcolored = true;
|
||||
std::istringstream iss2(col);
|
||||
fcolor[fi] = File_scanner_OFF::get_color_from_line(iss2);
|
||||
}
|
||||
} else {
|
||||
if(fcolored){
|
||||
fcolor[fi] = File_scanner_OFF::get_color_from_line(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
return is.good();
|
||||
}
|
||||
|
||||
|
||||
template <typename P>
|
||||
bool read_off(std::istream& is, Surface_mesh<P>& sm)
|
||||
{
|
||||
return read_off(is, sm, parameters::all_default());
|
||||
}
|
||||
|
||||
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
template <typename P>
|
||||
bool read_ply(std::istream& is, Surface_mesh<P>& sm)
|
||||
{
|
||||
std::string dummy;
|
||||
return read_ply (is, sm, dummy);
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/// Extracts the surface mesh from an input stream in Ascii or
|
||||
/// Binary PLY format and appends it to the surface mesh `sm`.
|
||||
///
|
||||
/// - the operator reads the vertex `point` property and the face
|
||||
/// `vertex_index` (or `vertex_indices`) property;
|
||||
/// - if three PLY properties `nx`, `ny` and `nz` with type `float`
|
||||
/// or `double` are found for vertices, a "v:normal" vertex
|
||||
/// property map is added;
|
||||
/// - if three PLY properties `red`, `green` and `blue` with type
|
||||
/// `uchar` are found for vertices, a "v:color" vertex property
|
||||
/// map is added;
|
||||
/// - if three PLY properties `red`, `green` and `blue` with type
|
||||
/// `uchar` are found for faces, a "f:color" face property map is
|
||||
/// added;
|
||||
/// - if any other PLY property is found, a "[s]:[name]" property map is
|
||||
/// added, where `[s]` is `v` for vertex and `f` for face, and
|
||||
/// `[name]` is the name of the PLY property.
|
||||
///
|
||||
/// The `comments` parameter can be omitted. If provided, it will be
|
||||
/// used to store the potential comments found in the PLY
|
||||
/// header. Each line starting by "comment " in the header is
|
||||
/// appended to the `comments` string (without the "comment " word).
|
||||
///
|
||||
/// \pre The data in the stream must represent a two-manifold. If this is not the case
|
||||
/// the `failbit` of `is` is set and the mesh cleared.
|
||||
/// \relates Surface_mesh
|
||||
|
||||
template <typename P>
|
||||
bool read_ply(std::istream& is, Surface_mesh<P>& sm, std::string& comments)
|
||||
{
|
||||
typedef typename Surface_mesh<P>::size_type size_type;
|
||||
|
||||
if(!is)
|
||||
{
|
||||
std::cerr << "Error: cannot open file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
IO::internal::PLY_reader reader;
|
||||
IO::internal::Surface_mesh_filler<P> filler(sm);
|
||||
|
||||
if (!(reader.init (is)))
|
||||
{
|
||||
is.setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
|
||||
comments = reader.comments();
|
||||
|
||||
for (std::size_t i = 0; i < reader.number_of_elements(); ++ i)
|
||||
{
|
||||
IO::internal::PLY_element& element = reader.element(i);
|
||||
|
||||
bool is_vertex = (element.name() == "vertex" || element.name() == "vertices");
|
||||
bool is_face = false;
|
||||
bool is_edge = false;
|
||||
bool is_halfedge = false;
|
||||
if (is_vertex)
|
||||
{
|
||||
sm.reserve(sm.number_of_vertices() + size_type(element.number_of_items()),
|
||||
sm.number_of_edges(),
|
||||
sm.number_of_faces());
|
||||
filler.instantiate_vertex_properties (element);
|
||||
}
|
||||
else
|
||||
is_face = (element.name() == "face" || element.name() == "faces");
|
||||
|
||||
if (is_face)
|
||||
{
|
||||
sm.reserve(sm.number_of_vertices(),
|
||||
sm.number_of_edges(),
|
||||
sm.number_of_faces() + size_type(element.number_of_items()));
|
||||
filler.instantiate_face_properties (element);
|
||||
}
|
||||
else
|
||||
is_edge = (element.name() == "edge");
|
||||
|
||||
if (is_edge)
|
||||
filler.instantiate_edge_properties (element);
|
||||
else
|
||||
is_halfedge = (element.name() == "halfedge");
|
||||
|
||||
if (is_halfedge)
|
||||
filler.instantiate_halfedge_properties (element);
|
||||
|
||||
for (std::size_t j = 0; j < element.number_of_items(); ++ j)
|
||||
{
|
||||
for (std::size_t k = 0; k < element.number_of_properties(); ++ k)
|
||||
{
|
||||
IO::internal::PLY_read_number* property = element.property(k);
|
||||
property->get (is);
|
||||
if (is.fail())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_vertex)
|
||||
filler.process_vertex_line (element);
|
||||
else if (is_face)
|
||||
{
|
||||
if (!filler.process_face_line (element))
|
||||
{
|
||||
is.setstate(std::ios::failbit);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (is_edge)
|
||||
filler.process_edge_line (element);
|
||||
else if (is_halfedge)
|
||||
filler.process_halfedge_line (element);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \relates Surface_mesh
|
||||
/// This operator calls `read_off(std::istream& is, CGAL::Surface_mesh& sm)`.
|
||||
/// \attention Up to %CGAL 4.10 this operator called `sm.clear()`.
|
||||
/// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`.
|
||||
template <typename P>
|
||||
std::istream& operator>>(std::istream& is, Surface_mesh<P>& sm)
|
||||
{
|
||||
read_off(is, sm);
|
||||
read_OFF(is, sm);
|
||||
return is;
|
||||
}
|
||||
|
||||
|
|
@ -3180,7 +2625,7 @@ namespace internal{
|
|||
}
|
||||
}
|
||||
|
||||
} // CGAL
|
||||
} // namespace CGAL
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,34 @@
|
|||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef Kernel::Point_3 Point;
|
||||
typedef CGAL::Surface_mesh<Point> SMesh;
|
||||
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
|
||||
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> SMesh;
|
||||
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
|
||||
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::ifstream in ("colored_tetra.ply");
|
||||
std::ifstream in("colored_tetra.ply");
|
||||
SMesh mesh;
|
||||
CGAL::read_ply (in, mesh);
|
||||
CGAL::read_PLY(in, mesh);
|
||||
|
||||
std::cerr << "Read mesh with " << mesh.number_of_vertices() << " vertices and "
|
||||
<< mesh.number_of_faces() << " faces" << std::endl;
|
||||
|
||||
std::cerr << "Properties associated with vertices:" << std::endl;
|
||||
std::vector<std::string> properties = mesh.properties<SMesh::Vertex_index>();
|
||||
for (std::size_t i = 0; i < properties.size(); ++ i)
|
||||
for(std::size_t i = 0; i < properties.size(); ++ i)
|
||||
std::cerr << " * " << properties[i] << std::endl;
|
||||
|
||||
std::cerr << "Properties associated with faces:" << std::endl;
|
||||
properties = mesh.properties<SMesh::Face_index>();
|
||||
for (std::size_t i = 0; i < properties.size(); ++ i)
|
||||
for(std::size_t i = 0; i < properties.size(); ++ i)
|
||||
std::cerr << " * " << properties[i] << std::endl;
|
||||
|
||||
mesh.add_property_map<SMesh::Edge_index, short>("id", 42);
|
||||
|
|
@ -35,12 +36,12 @@ int main()
|
|||
mesh.add_property_map<SMesh::Halfedge_index, float>("v", 37.f);
|
||||
|
||||
// Append second mesh
|
||||
std::ifstream in2 ("tetra.ply");
|
||||
CGAL::read_ply (in2, mesh);
|
||||
std::ifstream in2("tetra.ply");
|
||||
CGAL::read_PLY(in2, mesh);
|
||||
|
||||
std::ofstream out ("out.ply");
|
||||
std::ofstream out("out.ply");
|
||||
// CGAL::set_binary_mode(out);
|
||||
CGAL::write_ply (out, mesh);
|
||||
CGAL::write_PLY(out, mesh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue