Rework Surface_mesh IO

This commit is contained in:
Mael Rouxel-Labbé 2020-01-28 18:36:30 +01:00
parent 65c1a4f81b
commit b1da380064
22 changed files with 799 additions and 1025 deletions

View File

@ -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

View File

@ -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();

View File

@ -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()); }

View File

@ -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})

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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'; }
};

View File

@ -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());
}

View File

@ -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()
{

View File

@ -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;

View File

@ -21,7 +21,7 @@
namespace CGAL {
// fwdS for the public interface
template<typename K>
template<typename P>
class Surface_mesh;
}

View File

@ -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

View File

@ -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 {
/*!
* 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,14 +48,14 @@ 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);
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;
return -1;
}
output.reserve(nb_meshes);
for(int i=0; i<nb_meshes; ++i)
{
@ -60,22 +64,20 @@ int read_3mf(const std::string& file_name,
PolygonRange triangles = all_polygons[i];
PointRange points = all_points[i];
std::vector<CGAL::Color> colors = all_colors[i];
// Create the surface mesh from scratch
std::size_t n(points.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,13 +86,13 @@ 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)
{
@ -98,20 +100,25 @@ int read_3mf(const std::string& file_name,
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.
}
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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -1,21 +1,22 @@
#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");
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;
@ -36,11 +37,11 @@ int main()
// Append second mesh
std::ifstream in2("tetra.ply");
CGAL::read_ply (in2, mesh);
CGAL::read_PLY(in2, mesh);
std::ofstream out("out.ply");
// CGAL::set_binary_mode(out);
CGAL::write_ply (out, mesh);
CGAL::write_PLY(out, mesh);
return 0;
}