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
|
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
||||||
//
|
//
|
||||||
// Author(s) : Maxime Gimeno
|
// Author(s) : Maxime Gimeno
|
||||||
|
// Mael Rouxel-Labbé
|
||||||
|
|
||||||
#ifndef CGAL_BGL_IO_GENERIC_FACEGRAPH_BUILDER_H
|
#ifndef CGAL_BGL_IO_GENERIC_FACEGRAPH_BUILDER_H
|
||||||
#define CGAL_BGL_IO_GENERIC_FACEGRAPH_BUILDER_H
|
#define CGAL_BGL_IO_GENERIC_FACEGRAPH_BUILDER_H
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ public:
|
||||||
if(has_face_colors)
|
if(has_face_colors)
|
||||||
{
|
{
|
||||||
const CGAL::Color& fc = get(fcm, f);
|
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();
|
m_writer.write_facet_end();
|
||||||
|
|
|
||||||
|
|
@ -60,30 +60,12 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
// Because some packages can provide overloads with the same signature to automatically initialize
|
||||||
} // namespace IO
|
// property maps (see Surface_mesh/IO/ for example)
|
||||||
|
|
||||||
/*!
|
|
||||||
\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
|
|
||||||
*/
|
|
||||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||||
bool read_OFF(std::istream& in,
|
bool read_OFF_BGL(std::istream& in,
|
||||||
FaceGraph& g,
|
FaceGraph& g,
|
||||||
const CGAL_BGL_NP_CLASS& np)
|
const CGAL_BGL_NP_CLASS& np)
|
||||||
{
|
{
|
||||||
typedef typename CGAL::GetVertexPointMap<FaceGraph, CGAL_BGL_NP_CLASS>::type VPM;
|
typedef typename CGAL::GetVertexPointMap<FaceGraph, CGAL_BGL_NP_CLASS>::type VPM;
|
||||||
typedef typename boost::property_traits<VPM>::value_type Point;
|
typedef typename boost::property_traits<VPM>::value_type Point;
|
||||||
|
|
@ -92,24 +74,36 @@ bool read_OFF(std::istream& in,
|
||||||
return builder(g, np);
|
return builder(g, np);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace IO
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\ingroup PkgBGLIOFct
|
\ingroup PkgBGLIOFct
|
||||||
|
|
||||||
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash,
|
reads the graph `g` from data in the OFF format. Ignores comment lines which start with a hash,
|
||||||
and lines with whitespace.
|
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
|
\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
|
\see \ref IOStreamOFF
|
||||||
*/
|
*/
|
||||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||||
bool read_OFF(const char* fname,
|
bool read_OFF(std::istream& in, FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||||
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);
|
std::ifstream in(fname);
|
||||||
return read_OFF(in, g, np);
|
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
|
/// 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
|
\ingroup PkgBGLIOFct
|
||||||
|
|
||||||
|
|
@ -149,27 +158,14 @@ bool read_OFF(const std::string& fname, FaceGraph& g) { return read_OFF(fname, g
|
||||||
\see \ref IOStreamOFF
|
\see \ref IOStreamOFF
|
||||||
*/
|
*/
|
||||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||||
bool write_OFF(std::ostream& os,
|
bool write_OFF(std::ostream& os, const FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||||
const FaceGraph& g,
|
|
||||||
const CGAL_BGL_NP_CLASS& np)
|
|
||||||
{
|
{
|
||||||
IO::internal::Generic_facegraph_printer<std::ostream, FaceGraph, CGAL::File_writer_OFF> printer(os);
|
return IO::internal::write_OFF_BGL(os, g, np);
|
||||||
return printer(g, np);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
// document that too
|
||||||
\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
|
|
||||||
*/
|
|
||||||
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
template <typename FaceGraph, typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||||
bool write_OFF(const char* fname,
|
bool write_OFF(const char* fname, const FaceGraph& g, const CGAL_BGL_NP_CLASS& np)
|
||||||
const FaceGraph& g,
|
|
||||||
const CGAL_BGL_NP_CLASS& np)
|
|
||||||
{
|
{
|
||||||
std::ofstream out(fname);
|
std::ofstream out(fname);
|
||||||
return write_OFF(out, g, np);
|
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);
|
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()); }
|
bool write_OFF(std::ostream& os, const FaceGraph& g) { return write_OFF(os, g, parameters::all_default()); }
|
||||||
template <typename FaceGraph>
|
template <typename FaceGraph>
|
||||||
bool write_OFF(const char* fname, const FaceGraph& g) { return write_OFF(fname, g, parameters::all_default()); }
|
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_wrl.cpp" )
|
||||||
|
|
||||||
|
create_single_source_cgal_program( "test_io.cpp" )
|
||||||
|
|
||||||
if(OpenMesh_FOUND)
|
if(OpenMesh_FOUND)
|
||||||
target_link_libraries( test_clear PRIVATE ${OPENMESH_LIBRARIES})
|
target_link_libraries( test_clear PRIVATE ${OPENMESH_LIBRARIES})
|
||||||
target_link_libraries( test_Euler_operations PRIVATE ${OPENMESH_LIBRARIES})
|
target_link_libraries( test_Euler_operations PRIVATE ${OPENMESH_LIBRARIES})
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include <CGAL/IO/OFF.h>
|
#include <CGAL/IO/OFF.h>
|
||||||
#include <CGAL/IO/OBJ.h>
|
#include <CGAL/IO/OBJ.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
#include "Scene_points_with_normal_item.h"
|
#include "Scene_points_with_normal_item.h"
|
||||||
|
|
||||||
#include <CGAL/IO/PLY.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/Polyhedron_demo_io_plugin_interface.h>
|
||||||
#include <CGAL/Three/Three.h>
|
#include <CGAL/Three/Three.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1510,9 +1510,14 @@ Scene_surface_mesh_item::load_obj(std::istream& in)
|
||||||
bool
|
bool
|
||||||
Scene_surface_mesh_item::save_obj(std::ostream& out) const
|
Scene_surface_mesh_item::save_obj(std::ostream& out) const
|
||||||
{
|
{
|
||||||
CGAL::File_writer_wavefront writer;
|
typename SMesh::template Property_map<typename SMesh::Vertex_index, EPICK::Vector_3> vnormals;
|
||||||
CGAL::generic_print_surface_mesh(out, *(d->smesh_), writer);
|
bool has_normals = false;
|
||||||
return out.good();
|
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
|
void
|
||||||
|
|
|
||||||
|
|
@ -461,12 +461,12 @@ struct Constant_property_map
|
||||||
Constant_property_map(const value_type& default_value = value_type()) : default_value (default_value) { }
|
Constant_property_map(const value_type& default_value = value_type()) : default_value (default_value) { }
|
||||||
|
|
||||||
/// Free function that returns `pm.default_value`.
|
/// Free function that returns `pm.default_value`.
|
||||||
inline friend value_type
|
inline friend
|
||||||
get (const Constant_property_map& pm, const key_type&){ return pm.default_value; }
|
const value_type& get (const Constant_property_map& pm, const key_type&) { return pm.default_value; }
|
||||||
|
|
||||||
/// Free function that does nothing.
|
/// Free function that does nothing.
|
||||||
inline friend void
|
inline friend
|
||||||
put (const Constant_property_map&, const key_type&, const value_type&) { }
|
void put (const Constant_property_map&, const key_type&, const value_type&) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \ingroup PkgPropertyMapRef
|
/// \ingroup PkgPropertyMapRef
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,9 @@ public:
|
||||||
bool operator()(std::vector<Point_3>& points,
|
bool operator()(std::vector<Point_3>& points,
|
||||||
std::vector<Polygon_3>& polygons)
|
std::vector<Polygon_3>& polygons)
|
||||||
{
|
{
|
||||||
|
if(m_out.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
m_writer.write_header(m_out, points.size(), 0, polygons.size());
|
m_writer.write_header(m_out, points.size(), 0, polygons.size());
|
||||||
for(std::size_t i=0, end=points.size(); i<end; ++i)
|
for(std::size_t i=0, end=points.size(); i<end; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,13 @@ namespace CGAL {
|
||||||
namespace IO {
|
namespace IO {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename Points, typename Faces, typename VertexNormalOutputIterator>
|
template <typename PointRange, typename PolygonRange, typename VertexNormalOutputIterator>
|
||||||
bool read_OBJ(std::istream& input,
|
bool read_OBJ(std::istream& is,
|
||||||
Points& points,
|
PointRange& points,
|
||||||
Faces& faces,
|
PolygonRange& faces,
|
||||||
VertexNormalOutputIterator vn_out)
|
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 CGAL::Kernel_traits<Point>::Kernel Kernel;
|
||||||
typedef typename Kernel::Vector_3 Normal;
|
typedef typename Kernel::Vector_3 Normal;
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ bool read_OBJ(std::istream& input,
|
||||||
Point p;
|
Point p;
|
||||||
std::string line;
|
std::string line;
|
||||||
|
|
||||||
while(getline(input, line))
|
while(getline(is, line))
|
||||||
{
|
{
|
||||||
if(line[0] == 'v' && line[1] == ' ')
|
if(line[0] == 'v' && line[1] == ' ')
|
||||||
{
|
{
|
||||||
|
|
@ -106,7 +106,7 @@ bool read_OBJ(std::istream& input,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !input.fail();
|
return !is.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
@ -114,16 +114,16 @@ bool read_OBJ(std::istream& input,
|
||||||
|
|
||||||
//! \ingroup IOstreamFunctions
|
//! \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 Points a `RandomAccessContainer` of `Point_3,
|
||||||
/// \tparam Faces a `RandomAccessContainer` of `RandomAccessContainer` of `std::size_t`
|
/// \tparam Faces a `RandomAccessContainer` of `RandomAccessContainer` of `std::size_t`
|
||||||
///
|
///
|
||||||
/// \see \ref IOStreamOBJ
|
/// \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,
|
bool read_OBJ(std::istream& is,
|
||||||
Points& points,
|
PointRange& points,
|
||||||
Faces& faces,
|
PolygonRange& faces,
|
||||||
const CGAL_BGL_NP_CLASS& np)
|
const CGAL_BGL_NP_CLASS& np)
|
||||||
{
|
{
|
||||||
using parameters::choose_parameter;
|
using parameters::choose_parameter;
|
||||||
|
|
@ -134,11 +134,44 @@ bool read_OBJ(std::istream& is,
|
||||||
CGAL::Emptyset_iterator()));
|
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
|
/// Write
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup IOstreamFunctions
|
* \ingroup IOstreamFunctions
|
||||||
*
|
*
|
||||||
|
|
@ -146,15 +179,28 @@ bool read_OBJ(std::istream& is,
|
||||||
*
|
*
|
||||||
* \see \ref IOStreamOBJ
|
* \see \ref IOStreamOBJ
|
||||||
*/
|
*/
|
||||||
template <class Point_3, class Polygon_3>
|
template <typename PointRange, typename PolygonRange>
|
||||||
bool write_OBJ(std::ostream& os,
|
bool write_OBJ(std::ostream& os,
|
||||||
std::vector<Point_3>& points,
|
PointRange& points,
|
||||||
std::vector<Polygon_3>& polygons)
|
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);
|
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
|
} // namespace CGAL
|
||||||
|
|
||||||
#endif // CGAL_IO_OBJ_H
|
#endif // CGAL_IO_OBJ_H
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ public:
|
||||||
}
|
}
|
||||||
void write_facet_begin(std::size_t) { out() << "f "; }
|
void write_facet_begin(std::size_t) { out() << "f "; }
|
||||||
void write_facet_vertex_index(std::size_t idx) { out() << ' ' << idx+1; }
|
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'; }
|
void write_facet_end() { out() << '\n'; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
#include <CGAL/Kernel_traits.h>
|
#include <CGAL/Kernel_traits.h>
|
||||||
#include <CGAL/use.h>
|
#include <CGAL/use.h>
|
||||||
|
|
||||||
|
#include <boost/range/value_type.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -36,26 +38,29 @@ namespace CGAL {
|
||||||
namespace IO {
|
namespace IO {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <typename Point_3, typename Polygon_3,
|
template <typename PointRange, typename PolygonRange,
|
||||||
typename VertexNormalOutputIterator,
|
typename VertexNormalOutputIterator,
|
||||||
typename VertexColorOutputIterator,
|
typename VertexColorOutputIterator,
|
||||||
typename VertexTextureOutputIterator,
|
typename VertexTextureOutputIterator,
|
||||||
typename FaceColorOutputIterator>
|
typename FaceColorOutputIterator>
|
||||||
bool read_OFF(std::istream& in,
|
bool read_OFF(std::istream& is,
|
||||||
std::vector<Point_3>& points,
|
PointRange& points,
|
||||||
std::vector<Polygon_3>& polygons,
|
PolygonRange& polygons,
|
||||||
VertexNormalOutputIterator vn_out,
|
VertexNormalOutputIterator vn_out,
|
||||||
VertexColorOutputIterator vc_out,
|
VertexColorOutputIterator vc_out,
|
||||||
VertexTextureOutputIterator vt_out,
|
VertexTextureOutputIterator vt_out,
|
||||||
FaceColorOutputIterator fc_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::Point_2 Texture;
|
||||||
typedef typename Kernel::Vector_3 Normal;
|
typedef typename Kernel::Vector_3 Normal;
|
||||||
typedef CGAL::Color Color;
|
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());
|
points.resize(scanner.size_of_vertices());
|
||||||
polygons.resize(scanner.size_of_facets());
|
polygons.resize(scanner.size_of_facets());
|
||||||
|
|
@ -82,7 +87,6 @@ bool read_OFF(std::istream& in,
|
||||||
*vc_out++ = Color(r,g,b);
|
*vc_out++ = Color(r,g,b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @fixme
|
|
||||||
if(scanner.has_textures())
|
if(scanner.has_textures())
|
||||||
{
|
{
|
||||||
double nx, ny, nw;
|
double nx, ny, nw;
|
||||||
|
|
@ -93,7 +97,7 @@ bool read_OFF(std::istream& in,
|
||||||
|
|
||||||
scanner.skip_to_next_vertex(i);
|
scanner.skip_to_next_vertex(i);
|
||||||
|
|
||||||
if(!in.good())
|
if(!is.good())
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,7 +107,7 @@ bool read_OFF(std::istream& in,
|
||||||
std::size_t no;
|
std::size_t no;
|
||||||
scanner.scan_facet(no, i);
|
scanner.scan_facet(no, i);
|
||||||
|
|
||||||
if(!in.good())
|
if(!is.good())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
IO::internal::resize(polygons[i], no);
|
IO::internal::resize(polygons[i], no);
|
||||||
|
|
@ -120,7 +124,7 @@ bool read_OFF(std::istream& in,
|
||||||
if(i == 0)
|
if(i == 0)
|
||||||
{
|
{
|
||||||
std::string col;
|
std::string col;
|
||||||
std::getline(in, col);
|
std::getline(is, col);
|
||||||
std::istringstream iss(col);
|
std::istringstream iss(col);
|
||||||
char ci =' ';
|
char ci =' ';
|
||||||
|
|
||||||
|
|
@ -139,7 +143,7 @@ bool read_OFF(std::istream& in,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return !in.fail();
|
return !is.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
@ -148,22 +152,22 @@ bool read_OFF(std::istream& in,
|
||||||
/*!
|
/*!
|
||||||
* \ingroup IOstreamFunctions
|
* \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
|
* @fixme re-add support for STOFF
|
||||||
*
|
*
|
||||||
* \see \ref IOStreamOFF
|
* \see \ref IOStreamOFF
|
||||||
*/
|
*/
|
||||||
template <typename Point_3, typename Polygon_3, typename NamedParameters>
|
template <typename PointRange, typename PolygonRange, typename NamedParameters>
|
||||||
bool read_OFF(std::istream& in,
|
bool read_OFF(std::istream& is,
|
||||||
std::vector<Point_3>& points, // @fixme doesn't need a vector specifically
|
PointRange& points,
|
||||||
std::vector<Polygon_3>& polygons,
|
PolygonRange& polygons,
|
||||||
const NamedParameters& np)
|
const NamedParameters& np)
|
||||||
{
|
{
|
||||||
using parameters::choose_parameter;
|
using parameters::choose_parameter;
|
||||||
using parameters::get_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),
|
choose_parameter(get_parameter(np, internal_np::vertex_normal_output_iterator),
|
||||||
CGAL::Emptyset_iterator()),
|
CGAL::Emptyset_iterator()),
|
||||||
choose_parameter(get_parameter(np, internal_np::vertex_color_output_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()));
|
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,
|
bool read_OFF(const char* fname,
|
||||||
std::vector<Point_3>& points,
|
PointRange& points,
|
||||||
std::vector<Polygon_3>& polygons,
|
PolygonRange& polygons,
|
||||||
const CGAL_BGL_NP_CLASS& np)
|
const CGAL_BGL_NP_CLASS& np)
|
||||||
{
|
{
|
||||||
std::ifstream in(fname);
|
std::ifstream in(fname);
|
||||||
return read_OFF(in, points, polygons, np);
|
return read_OFF(in, points, polygons, np);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 std::string& fname,
|
bool read_OFF(const std::string& fname, PointRange& points, PolygonRange& polygons, const CGAL_BGL_NP_CLASS& np)
|
||||||
std::vector<Point_3>& points,
|
|
||||||
std::vector<Polygon_3>& polygons,
|
|
||||||
const CGAL_BGL_NP_CLASS& np)
|
|
||||||
{
|
{
|
||||||
return read_OFF(fname.c_str(), points, polygons, np);
|
return read_OFF(fname.c_str(), points, polygons, np);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Point_3, typename Polygon_3>
|
template <typename PointRange, typename PolygonRange>
|
||||||
bool read_OFF(std::istream& is,
|
bool read_OFF(std::istream& is, PointRange& points, PolygonRange& polygons)
|
||||||
std::vector<Point_3>& points,
|
|
||||||
std::vector<Polygon_3>& polygons)
|
|
||||||
{
|
{
|
||||||
return read_OFF(is, points, polygons, parameters::all_default());
|
return read_OFF(is, points, polygons, parameters::all_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Point_3, typename Polygon_3>
|
template <typename PointRange, typename PolygonRange>
|
||||||
bool read_OFF(const char* fname,
|
bool read_OFF(const char* fname, PointRange& points, PolygonRange& polygons)
|
||||||
std::vector<Point_3>& points,
|
|
||||||
std::vector<Polygon_3>& polygons)
|
|
||||||
{
|
{
|
||||||
return read_OFF(fname, points, polygons, parameters::all_default());
|
return read_OFF(fname, points, polygons, parameters::all_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Point_3, typename Polygon_3>
|
template <typename PointRange, typename PolygonRange>
|
||||||
bool read_OFF(const std::string& fname,
|
bool read_OFF(const std::string& fname, PointRange& points, PolygonRange& polygons)
|
||||||
std::vector<Point_3>& points,
|
|
||||||
std::vector<Polygon_3>& polygons)
|
|
||||||
{
|
{
|
||||||
return read_OFF(fname, points, polygons, parameters::all_default());
|
return read_OFF(fname, points, polygons, parameters::all_default());
|
||||||
}
|
}
|
||||||
|
|
@ -228,20 +223,20 @@ bool read_OFF(const std::string& fname,
|
||||||
*
|
*
|
||||||
* \see \ref IOStreamOFF
|
* \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,
|
bool write_OFF(std::ostream& os,
|
||||||
std::vector<Point_3>& points,
|
PointRange& points,
|
||||||
std::vector<Polygon_3>& polygons,
|
PolygonRange& polygons,
|
||||||
const NamedParameters& np)
|
const CGAL_BGL_NP_CLASS& np)
|
||||||
{
|
{
|
||||||
Generic_writer<std::ostream, File_writer_OFF> writer(os);
|
Generic_writer<std::ostream, File_writer_OFF> writer(os);
|
||||||
return writer(points, polygons, np);
|
return writer(points, polygons, np);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Point_3, class Polygon_3>
|
template <typename PointRange, typename PolygonRange>
|
||||||
bool write_OFF(std::ostream& os,
|
bool write_OFF(std::ostream& os,
|
||||||
std::vector<Point_3>& points,
|
PointRange& points,
|
||||||
std::vector<Polygon_3>& polygons)
|
PolygonRange& polygons)
|
||||||
{
|
{
|
||||||
return write_OFF(os, points, polygons, parameters::all_default());
|
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)
|
void write_vertex_color(const double r, const double g, const double b)
|
||||||
{
|
{
|
||||||
// @todo
|
if(m_header.binary())
|
||||||
CGAL_assertion(false);
|
{
|
||||||
|
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
|
if(m_header.binary())
|
||||||
CGAL_assertion(false);
|
{
|
||||||
|
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()
|
void write_facet_header()
|
||||||
|
|
@ -135,7 +150,7 @@ public:
|
||||||
out() << ' ' << index;
|
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()
|
void write_facet_end()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,10 @@ returns the printing mode of the %IO stream `s`.
|
||||||
\sa `CGAL::is_binary()`
|
\sa `CGAL::is_binary()`
|
||||||
\sa `CGAL::is_pretty()`
|
\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
|
\ingroup PkgStreamSupportRef
|
||||||
|
|
@ -414,7 +417,7 @@ Returns the previous mode of `s`.
|
||||||
\sa `CGAL::is_binary()`
|
\sa `CGAL::is_binary()`
|
||||||
\sa `CGAL::is_pretty()`
|
\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);
|
IO::Mode m = get_mode(i);
|
||||||
i.iword(IO::Static::get_mode()) = IO::ASCII;
|
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_binary()`
|
||||||
\sa `CGAL::is_pretty()`
|
\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);
|
IO::Mode m = get_mode(i);
|
||||||
i.iword(IO::Static::get_mode()) = IO::BINARY;
|
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_binary()`
|
||||||
\sa `CGAL::is_pretty()`
|
\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);
|
IO::Mode m = get_mode(i);
|
||||||
i.iword(IO::Static::get_mode()) = IO::PRETTY;
|
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_binary()`
|
||||||
\sa `CGAL::is_pretty()`
|
\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);
|
IO::Mode old = get_mode(i);
|
||||||
i.iword(IO::Static::get_mode()) = m;
|
i.iword(IO::Static::get_mode()) = m;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
// fwdS for the public interface
|
// fwdS for the public interface
|
||||||
template<typename K>
|
template<typename P>
|
||||||
class Surface_mesh;
|
class Surface_mesh;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,15 @@
|
||||||
|
|
||||||
#include <CGAL/license/Surface_mesh.h>
|
#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/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/Kernel_traits.h>
|
||||||
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
|
#include <CGAL/use.h>
|
||||||
|
|
||||||
#include <boost/array.hpp>
|
#include <boost/array.hpp>
|
||||||
|
|
||||||
|
|
@ -34,194 +37,7 @@
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
namespace internal {
|
// @todo move that to read_polygon_mesh in BGL
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \addtogroup PkgSurfaceMeshIO
|
/// \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
|
#if 0
|
||||||
/// Read a file into a `Surface_mesh`. The extension of the
|
/// Read a file into a `Surface_mesh`. The extension of the
|
||||||
/// filename determines which reader is used.
|
/// filename determines which reader is used.
|
||||||
|
|
@ -330,7 +62,8 @@ bool write_off(const Surface_mesh<K>& mesh, const std::string& filename)
|
||||||
///
|
///
|
||||||
#endif
|
#endif
|
||||||
template <typename K>
|
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
|
// clear mesh before reading from file
|
||||||
mesh.clear();
|
mesh.clear();
|
||||||
|
|
||||||
|
|
@ -382,6 +115,8 @@ bool write_mesh(const Surface_mesh<K>& mesh, const std::string& filename)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
} // namespace CGAL
|
} // namespace CGAL
|
||||||
|
|
||||||
#endif // CGAL_SURFACE_MESH_IO_H
|
#endif // CGAL_SURFACE_MESH_IO_H
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,18 @@
|
||||||
#ifndef CGAL_SURFACE_MESH_IO_3MF_H
|
#ifndef CGAL_SURFACE_MESH_IO_3MF_H
|
||||||
#define 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/Surface_mesh.h>
|
||||||
|
|
||||||
#include <CGAL/IO/3MF.h>
|
#include <CGAL/IO/3MF.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace CGAL {
|
||||||
|
|
||||||
namespace CGAL{
|
|
||||||
/*!
|
/*!
|
||||||
* Extracts the surface meshes from an input 3mf file and appends it to `output`.
|
* Extracts the surface meshes from an input 3mf file and appends it to `output`.
|
||||||
*\tparam Point the Point type of the output meshes.
|
*\tparam Point the Point type of the output meshes.
|
||||||
|
|
@ -27,55 +32,52 @@ namespace CGAL{
|
||||||
* \param output a `std::vector` containing the `CGAL::Surface_mesh`s that will be filled by this function.
|
* \param output a `std::vector` containing the `CGAL::Surface_mesh`s that will be filled by this function.
|
||||||
* \return the number of extracted meshes.
|
* \return the number of extracted meshes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename Point>
|
template<typename Point>
|
||||||
int read_3mf(const std::string& file_name,
|
int read_3mf(const std::string& file_name,
|
||||||
std::vector<CGAL::Surface_mesh<Point> >& output)
|
std::vector<CGAL::Surface_mesh<Point> >& output)
|
||||||
{
|
{
|
||||||
typedef std::vector<Point> PointRange;
|
typedef std::vector<Point> PointRange;
|
||||||
typedef std::vector<std::size_t> Polygon;
|
typedef std::vector<std::size_t> Polygon;
|
||||||
typedef std::vector<Polygon> PolygonRange;
|
typedef std::vector<Polygon> PolygonRange;
|
||||||
typedef CGAL::Surface_mesh<Point> SMesh;
|
typedef CGAL::Surface_mesh<Point> SMesh;
|
||||||
typedef typename SMesh::Vertex_index Vertex_index;
|
typedef typename SMesh::Vertex_index Vertex_index;
|
||||||
typedef typename SMesh::Face_index Face_index;
|
typedef typename SMesh::Face_index Face_index;
|
||||||
|
|
||||||
std::vector<PointRange> all_points;
|
std::vector<PointRange> all_points;
|
||||||
std::vector<PolygonRange> all_polygons;
|
std::vector<PolygonRange> all_polygons;
|
||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
std::vector<std::vector<CGAL::Color> > all_colors;
|
std::vector<std::vector<CGAL::Color> > all_colors;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int nb_meshes =
|
|
||||||
CGAL::read_triangle_soups_from_3mf(file_name,
|
int nb_meshes = CGAL::read_triangle_soups_from_3mf(file_name, all_points, all_polygons, all_colors, names);
|
||||||
all_points, all_polygons, all_colors, names);
|
if(nb_meshes < 0)
|
||||||
if(nb_meshes < 0 )
|
|
||||||
{
|
{
|
||||||
std::cerr << "Error in reading meshes."<<std::endl;
|
std::cerr << "Error in reading meshes." << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
output.reserve(nb_meshes);
|
output.reserve(nb_meshes);
|
||||||
for(int i = 0; i< nb_meshes; ++i)
|
for(int i=0; i<nb_meshes; ++i)
|
||||||
{
|
{
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
SMesh sm;
|
SMesh sm;
|
||||||
PolygonRange triangles = all_polygons[i];
|
PolygonRange triangles = all_polygons[i];
|
||||||
PointRange points = all_points[i];
|
PointRange points = all_points[i];
|
||||||
std::vector<CGAL::Color> colors = all_colors[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());
|
std::size_t n(points.size());
|
||||||
sm.reserve(n,0, triangles.size());
|
sm.reserve(n, 0, triangles.size());
|
||||||
for(const Point& p : points)
|
for(const Point& p : points)
|
||||||
{
|
|
||||||
sm.add_vertex(p);
|
sm.add_vertex(p);
|
||||||
}
|
|
||||||
|
|
||||||
for(Polygon& triangle : triangles)
|
for(Polygon& triangle : triangles)
|
||||||
{
|
{
|
||||||
std::vector<Vertex_index> face;
|
std::vector<Vertex_index> face;
|
||||||
face.reserve(triangle.size());
|
face.reserve(triangle.size());
|
||||||
for(auto index : triangle)
|
for(std::size_t index : triangle)
|
||||||
{
|
|
||||||
face.push_back(Vertex_index(index));
|
face.push_back(Vertex_index(index));
|
||||||
}
|
|
||||||
Face_index fi = sm.add_face(face);
|
Face_index fi = sm.add_face(face);
|
||||||
if(fi == sm.null_face())
|
if(fi == sm.null_face())
|
||||||
{
|
{
|
||||||
|
|
@ -84,34 +86,39 @@ int read_3mf(const std::string& file_name,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(skip)
|
if(skip)
|
||||||
continue;
|
continue;
|
||||||
//end constructin the surface mesh from scratch
|
|
||||||
|
|
||||||
CGAL::Color first = colors.front();
|
const Color& first = colors.front();
|
||||||
bool need_pmap = false;
|
bool need_pmap = false;
|
||||||
for(auto color : colors)
|
for(const Color& color : colors)
|
||||||
{
|
{
|
||||||
if (color != first)
|
if(color != first)
|
||||||
{
|
{
|
||||||
need_pmap = true;
|
need_pmap = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(need_pmap)
|
if(need_pmap)
|
||||||
{
|
{
|
||||||
typename SMesh::template Property_map<Face_index, CGAL::Color> fcolor =
|
typename SMesh::template Property_map<Face_index, CGAL::Color> fcolor =
|
||||||
sm.template add_property_map<Face_index,CGAL::Color>("f:color",first).first;
|
sm.template add_property_map<Face_index,CGAL::Color>("f:color", first).first;
|
||||||
for(std::size_t pid = 0; pid < colors.size(); ++pid)
|
|
||||||
{
|
for(std::size_t pid=0, cs=colors.size(); pid<cs; ++pid)
|
||||||
put(fcolor, Face_index(pid), colors[pid]);//should work bc mesh is just created and shouldn't have any destroyed face.
|
put(fcolor, Face_index(pid), colors[pid]); // there can't have any deleted face yet
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
output.push_back(sm);
|
output.push_back(sm);
|
||||||
++result;
|
++result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}//end CGAL
|
} // namespace CGAL
|
||||||
#endif // CGAL_SURFACE_MESH_3MF_H
|
|
||||||
|
#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
|
#ifndef CGAL_SURFACE_MESH_IO_PLY
|
||||||
#define 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>
|
#include <CGAL/IO/PLY.h>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
namespace IO {
|
namespace IO {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
|
||||||
|
|
||||||
template <typename Point>
|
template <typename Point>
|
||||||
class Surface_mesh_filler
|
class Surface_mesh_filler
|
||||||
{
|
{
|
||||||
|
|
@ -394,7 +394,7 @@ template <typename Point>
|
||||||
bool fill_simplex_specific_header(std::ostream& os,
|
bool fill_simplex_specific_header(std::ostream& os,
|
||||||
const Surface_mesh<Point>& sm,
|
const Surface_mesh<Point>& sm,
|
||||||
std::vector<Abstract_property_printer<
|
std::vector<Abstract_property_printer<
|
||||||
typename Surface_mesh<Point>::Vertex_index>*>& printers,
|
typename Surface_mesh<Point>::Vertex_index>*>& printers,
|
||||||
const std::string& prop)
|
const std::string& prop)
|
||||||
{
|
{
|
||||||
typedef Surface_mesh<Point> SMesh;
|
typedef Surface_mesh<Point> SMesh;
|
||||||
|
|
@ -695,10 +695,331 @@ void fill_header(std::ostream& os, const Surface_mesh<Point>& sm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace IO
|
} // 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
|
} // namespace CGAL
|
||||||
|
|
||||||
|
#endif // !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
||||||
|
|
||||||
#endif // CGAL_SURFACE_MESH_IO_PLY
|
#endif // CGAL_SURFACE_MESH_IO_PLY
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
#ifndef CGAL_SURFACE_MESH_PROPERTY_H
|
#ifndef CGAL_SURFACE_MESH_PROPERTY_H
|
||||||
#define CGAL_SURFACE_MESH_PROPERTY_H
|
#define CGAL_SURFACE_MESH_PROPERTY_H
|
||||||
|
|
||||||
|
|
@ -18,13 +17,13 @@
|
||||||
|
|
||||||
#ifndef DOXYGEN_RUNNING
|
#ifndef DOXYGEN_RUNNING
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
#include <CGAL/property_map.h>
|
|
||||||
#include <CGAL/assertions.h>
|
#include <CGAL/assertions.h>
|
||||||
|
#include <CGAL/property_map.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
|
|
||||||
#ifndef DOXYGEN_RUNNING
|
#ifndef DOXYGEN_RUNNING
|
||||||
/// Base class for vertex, halfedge, edge, and face index.
|
/// Base class for vertex, halfedge, edge, and face index.
|
||||||
///
|
///
|
||||||
|
|
@ -2126,577 +2125,23 @@ private: //------------------------------------------------------- private data
|
||||||
return sm;
|
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
|
/// \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>
|
template <typename P>
|
||||||
std::ostream& operator<<(std::ostream& os, const Surface_mesh<P>& sm)
|
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;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
|
|
||||||
|
|
||||||
/// \relates Surface_mesh
|
/// \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
|
/// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`.
|
||||||
/// 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()`.
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
std::istream& operator>>(std::istream& is, Surface_mesh<P>& sm)
|
std::istream& operator>>(std::istream& is, Surface_mesh<P>& sm)
|
||||||
{
|
{
|
||||||
read_off(is, sm);
|
read_OFF(is, sm);
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3180,8 +2625,8 @@ namespace internal{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // CGAL
|
} // namespace CGAL
|
||||||
|
|
||||||
#ifndef DOXYGEN_RUNNING
|
#ifndef DOXYGEN_RUNNING
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,34 @@
|
||||||
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
#include <CGAL/Surface_mesh/Surface_mesh.h>
|
||||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
typedef Kernel::Point_3 Point;
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
std::ifstream in ("colored_tetra.ply");
|
std::ifstream in("colored_tetra.ply");
|
||||||
SMesh mesh;
|
SMesh mesh;
|
||||||
CGAL::read_ply (in, mesh);
|
CGAL::read_PLY(in, mesh);
|
||||||
|
|
||||||
std::cerr << "Read mesh with " << mesh.number_of_vertices() << " vertices and "
|
std::cerr << "Read mesh with " << mesh.number_of_vertices() << " vertices and "
|
||||||
<< mesh.number_of_faces() << " faces" << std::endl;
|
<< mesh.number_of_faces() << " faces" << std::endl;
|
||||||
|
|
||||||
std::cerr << "Properties associated with vertices:" << std::endl;
|
std::cerr << "Properties associated with vertices:" << std::endl;
|
||||||
std::vector<std::string> properties = mesh.properties<SMesh::Vertex_index>();
|
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[i] << std::endl;
|
||||||
|
|
||||||
std::cerr << "Properties associated with faces:" << std::endl;
|
std::cerr << "Properties associated with faces:" << std::endl;
|
||||||
properties = mesh.properties<SMesh::Face_index>();
|
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;
|
std::cerr << " * " << properties[i] << std::endl;
|
||||||
|
|
||||||
mesh.add_property_map<SMesh::Edge_index, short>("id", 42);
|
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);
|
mesh.add_property_map<SMesh::Halfedge_index, float>("v", 37.f);
|
||||||
|
|
||||||
// Append second mesh
|
// Append second mesh
|
||||||
std::ifstream in2 ("tetra.ply");
|
std::ifstream in2("tetra.ply");
|
||||||
CGAL::read_ply (in2, mesh);
|
CGAL::read_PLY(in2, mesh);
|
||||||
|
|
||||||
std::ofstream out ("out.ply");
|
std::ofstream out("out.ply");
|
||||||
// CGAL::set_binary_mode(out);
|
// CGAL::set_binary_mode(out);
|
||||||
CGAL::write_ply (out, mesh);
|
CGAL::write_PLY(out, mesh);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue