Merge pull request #3636 from sgiraudot/Surface_mesh-PLY_IO-GF

[Small Feature] Surface Mesh PLY IO
This commit is contained in:
Laurent Rineau 2019-05-06 15:46:07 +02:00
commit 008a75d439
18 changed files with 2334 additions and 1116 deletions

View File

@ -35,87 +35,12 @@
#include <CGAL/IO/read_las_points.h>
#include <CGAL/IO/write_las_points.h>
#endif // LAS
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/IO/write_ply_points.h>
#include <CGAL/IO/PLY.h>
namespace CGAL {
namespace internal
{
template <typename Point, typename Vector>
class Abstract_property_printer
{
public:
virtual ~Abstract_property_printer() { }
virtual void print (std::ostream& stream, const typename CGAL::Point_set_3<Point,Vector>::Index& index) = 0;
};
template <typename Point, typename Vector, typename Type>
class Property_printer : public Abstract_property_printer<Point, Vector>
{
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
typedef typename Point_set::template Property_map<Type> Pmap;
Pmap m_pmap;
public:
Property_printer (const Pmap& pmap) : m_pmap (pmap)
{
}
virtual void print(std::ostream& stream, const typename CGAL::Point_set_3<Point,Vector>::Index& index)
{
stream << get(m_pmap, index);
}
};
template <typename Point, typename Vector, typename Type>
class Simple_property_printer : public Abstract_property_printer<Point, Vector>
{
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
typedef typename Point_set::template Property_map<Type> Pmap;
Pmap m_pmap;
public:
Simple_property_printer (const Pmap& pmap) : m_pmap (pmap)
{
}
virtual void print(std::ostream& stream, const typename CGAL::Point_set_3<Point,Vector>::Index& index)
{
if (get_mode(stream) == IO::ASCII)
stream << get(m_pmap, index);
else
{
Type t = get (m_pmap, index);
stream.write (reinterpret_cast<char*>(&t), sizeof(t));
}
}
};
template <typename Point, typename Vector, typename Type>
class Char_property_printer : public Abstract_property_printer<Point, Vector>
{
typedef typename CGAL::Point_set_3<Point, Vector> Point_set;
typedef typename Point_set::template Property_map<Type> Pmap;
Pmap m_pmap;
public:
Char_property_printer (const Pmap& pmap) : m_pmap (pmap)
{
}
virtual void print(std::ostream& stream, const typename CGAL::Point_set_3<Point,Vector>::Index& index)
{
if (get_mode(stream) == IO::ASCII)
stream << int(get(m_pmap, index));
else
{
Type t = get (m_pmap, index);
stream.write (reinterpret_cast<char*>(&t), sizeof(t));
}
}
};
namespace PLY
{
@ -365,19 +290,42 @@ read_off_point_set(
}
/// \cond SKIP_IN_MANUAL
template <typename Point, typename Vector>
bool
read_ply_point_set(
std::istream& stream, ///< input stream.
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
{
std::string dummy;
return read_ply_point_set (stream, point_set, dummy);
}
/// \endcond
/*!
\ingroup PkgPointSet3IO
Reads a point set with properties from an input stream in Ascii or
Binary PLY format.
- the operator reads the vertex `point` property;
- if three PLY properties `nx`, `ny` and `nz` with type `float`
or `double` are found, the normal map is added;
- if any other PLY property is found, a "[name]" property map is
added, where `[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).
*/
template <typename Point, typename Vector>
bool
read_ply_point_set(
std::istream& stream, ///< input stream.
#ifdef DOXYGEN_RUNNING
CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
#else
CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
std::string* comments = NULL) ///< recover PLY comments
#endif
std::string& comments) ///< PLY comments.
{
if(!stream)
{
@ -394,14 +342,14 @@ read_ply_point_set(
return false;
}
if (comments != NULL)
*comments = reader.comments();
comments = reader.comments();
for (std::size_t i = 0; i < reader.number_of_elements(); ++ i)
{
internal::PLY::PLY_element& element = reader.element(i);
if (element.name() == "vertex" || element.name() == "vertices")
bool is_vertex = (element.name() == "vertex" || element.name() == "vertices");
if (is_vertex)
{
point_set.reserve (element.number_of_items());
filler.instantiate_properties (element);
@ -417,7 +365,7 @@ read_ply_point_set(
return false;
}
if (element.name() == "vertex" || element.name() == "vertices")
if (is_vertex)
filler.process_line (element);
}
}
@ -427,27 +375,46 @@ read_ply_point_set(
/*!
\ingroup PkgPointSet3IO
Writes a point set with properties in an output stream in PLY
format.
If found, the normal map is inserted to the stream. All other
properties with simple types are inserted in the stream.
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 Point, typename Vector>
bool
write_ply_point_set(
std::ostream& stream, ///< output stream.
#ifdef DOXYGEN_RUNNING
const CGAL::Point_set_3<Point, Vector>& point_set) ///< point set
#else
const CGAL::Point_set_3<Point, Vector>& point_set, ///< point set
std::string* comments = NULL) ///< write PLY comments
#endif
const CGAL::Point_set_3<Point, Vector>& point_set, ///< point set.
const std::string& comments = std::string()) ///< PLY comments.
{
typedef CGAL::Point_set_3<Point, Vector> Point_set;
typedef typename Point_set::Index Index;
typedef typename Point_set::Point_map Point_map;
typedef typename Point_set::Vector_map Vector_map;
typedef typename Point_set::template Property_map<boost::int8_t> Int8_map;
typedef typename Point_set::template Property_map<boost::uint8_t> Uint8_map;
typedef typename Point_set::template Property_map<boost::int16_t> Int16_map;
typedef typename Point_set::template Property_map<boost::uint16_t> Uint16_map;
typedef typename Point_set::template Property_map<boost::int32_t> Int32_map;
typedef typename Point_set::template Property_map<boost::uint32_t> Uint32_map;
typedef typename Point_set::template Property_map<boost::int64_t> Int64_map;
typedef typename Point_set::template Property_map<boost::uint64_t> Uint64_map;
typedef typename Point_set::template Property_map<float> Float_map;
typedef typename Point_set::template Property_map<double> Double_map;
stream << "ply" << std::endl
<< ((get_mode(stream) == IO::BINARY) ? "format binary_little_endian 1.0" : "format ascii 1.0") << std::endl
<< "comment Generated by the CGAL library" << std::endl;
if (comments != NULL)
if (comments != std::string())
{
std::istringstream iss (*comments);
std::istringstream iss (comments);
std::string line;
while (getline(iss, line))
{
@ -459,7 +426,7 @@ write_ply_point_set(
stream << "element vertex " << point_set.number_of_points() << std::endl;
std::vector<std::string> prop = point_set.base().properties();
std::vector<internal::Abstract_property_printer<Point, Vector>*> printers;
std::vector<internal::PLY::Abstract_property_printer<Index>*> printers;
for (std::size_t i = 0; i < prop.size(); ++ i)
{
@ -468,7 +435,7 @@ write_ply_point_set(
if (prop[i] == "point")
{
if (boost::is_same<typename GetFTFromMap<typename Point_set::Point_map>::type, float>::value)
if (boost::is_same<typename Get_FT_from_map<typename Point_set::Point_map>::type, float>::value)
{
stream << "property float x" << std::endl
<< "property float y" << std::endl
@ -480,86 +447,125 @@ write_ply_point_set(
<< "property double y" << std::endl
<< "property double z" << std::endl;
}
printers.push_back (new internal::Property_printer<Point,Vector,Point>(point_set.point_map()));
printers.push_back (new internal::PLY::Property_printer<Index,Point_map>(point_set.point_map()));
continue;
}
if (prop[i] == "normal")
{
stream << "property double nx" << std::endl
<< "property double ny" << std::endl
<< "property double nz" << std::endl;
printers.push_back (new internal::Property_printer<Point,Vector,Vector>(point_set.normal_map()));
if (boost::is_same<typename Get_FT_from_map<typename Point_set::Vector_map>::type, float>::value)
{
stream << "property float nx" << std::endl
<< "property float ny" << std::endl
<< "property float nz" << std::endl;
}
else
{
stream << "property double nx" << std::endl
<< "property double ny" << std::endl
<< "property double nz" << std::endl;
}
printers.push_back (new internal::PLY::Property_printer<Index,Vector_map>(point_set.normal_map()));
continue;
}
bool okay = false;
{
typename Point_set::template Property_map<boost::int8_t> pmap;
Int8_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::int8_t>(prop[i]);
if (okay)
{
stream << "property char " << prop[i] << std::endl;
printers.push_back (new internal::Char_property_printer<Point,Vector,boost::int8_t>(pmap));
printers.push_back (new internal::PLY::Char_property_printer<Index,Int8_map>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::uint8_t> pmap;
Uint8_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::uint8_t>(prop[i]);
if (okay)
{
stream << "property uchar " << prop[i] << std::endl;
printers.push_back (new internal::Char_property_printer<Point,Vector,boost::uint8_t>(pmap));
printers.push_back (new internal::PLY::Char_property_printer<Index,Uint8_map>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::int16_t> pmap;
Int16_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::int16_t>(prop[i]);
if (okay)
{
stream << "property short " << prop[i] << std::endl;
printers.push_back (new internal::Simple_property_printer<Point,Vector,boost::int16_t>(pmap));
printers.push_back (new internal::PLY::Simple_property_printer<Index,Int16_map>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::uint16_t> pmap;
Uint16_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::uint16_t>(prop[i]);
if (okay)
{
stream << "property ushort " << prop[i] << std::endl;
printers.push_back (new internal::Simple_property_printer<Point,Vector,boost::uint16_t>(pmap));
printers.push_back (new internal::PLY::Simple_property_printer<Index,Uint16_map>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<boost::int32_t> pmap;
Int32_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::int32_t>(prop[i]);
if (okay)
{
stream << "property int " << prop[i] << std::endl;
printers.push_back (new internal::Simple_property_printer<Point,Vector,boost::int32_t>(pmap));
printers.push_back (new internal::PLY::Simple_property_printer<Index,Int32_map>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<float> pmap;
Uint32_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::uint32_t>(prop[i]);
if (okay)
{
stream << "property uint " << prop[i] << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Index,Uint32_map>(pmap));
continue;
}
}
{
Int64_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::int64_t>(prop[i]);
if (okay)
{
stream << "property int " << prop[i] << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Index,Int64_map,boost::int32_t>(pmap));
continue;
}
}
{
Uint64_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<boost::uint64_t>(prop[i]);
if (okay)
{
stream << "property uint " << prop[i] << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Index,Uint64_map,boost::uint32_t>(pmap));
continue;
}
}
{
Float_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<float>(prop[i]);
if (okay)
{
stream << "property float " << prop[i] << std::endl;
printers.push_back (new internal::Simple_property_printer<Point,Vector,float>(pmap));
printers.push_back (new internal::PLY::Simple_property_printer<Index,Float_map>(pmap));
continue;
}
}
{
typename Point_set::template Property_map<double> pmap;
Double_map pmap;
boost::tie (pmap, okay) = point_set.template property_map<double>(prop[i]);
if (okay)
{
stream << "property double " << prop[i] << std::endl;
printers.push_back (new internal::Simple_property_printer<Point,Vector,double>(pmap));
printers.push_back (new internal::PLY::Simple_property_printer<Index,Double_map>(pmap));
continue;
}
}

View File

@ -27,6 +27,7 @@
#include <tuple>
#include <CGAL/IO/PLY.h>
#include <CGAL/property_map.h>
#include <CGAL/value_type_traits.h>
#include <CGAL/point_set_processing_assertions.h>
@ -43,36 +44,9 @@
#include <sstream>
#include <string>
#define TRY_TO_GENERATE_PROPERTY(STD_TYPE, T_TYPE, TYPE) \
if (type == STD_TYPE || type == T_TYPE) \
m_elements.back().add_property (new PLY_read_typed_number< TYPE > (name, format))
#define TRY_TO_GENERATE_SIZED_LIST_PROPERTY(STD_SIZE_TYPE, T_SIZE_TYPE, SIZE_TYPE, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE) \
if ((size_type == STD_SIZE_TYPE || size_type == T_SIZE_TYPE) && \
(index_type == STD_INDEX_TYPE || index_type == T_INDEX_TYPE)) \
m_elements.back().add_property (new PLY_read_typed_list_with_typed_size< SIZE_TYPE , INDEX_TYPE > (name, format))
#define TRY_TO_GENERATE_LIST_PROPERTY(STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE) \
TRY_TO_GENERATE_SIZED_LIST_PROPERTY("uchar", "uint8", boost::uint8_t, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE); \
else TRY_TO_GENERATE_SIZED_LIST_PROPERTY("ushort", "uint16", boost::uint16_t, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE); \
else TRY_TO_GENERATE_SIZED_LIST_PROPERTY("uint", "uint32", boost::uint32_t, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE)
namespace CGAL {
// PLY types:
// name type number of bytes
// ---------------------------------------
// char character 1
// uchar unsigned character 1
// short short integer 2
// ushort unsigned short integer 2
// int integer 4
// uint unsigned integer 4
// float single-precision float 4
// double double-precision float 8
#ifdef DOXYGEN_RUNNING // Document some parts from Stream_support here for convenience
/**
\ingroup PkgPointSetProcessing3IOPly
@ -88,23 +62,6 @@ namespace CGAL {
PLY_property (const char* name) : name (name) { }
};
/// \cond SKIP_IN_MANUAL
// Use a double property for all kernels...
template <typename FT> struct Convert_FT { typedef double type; };
// ...except if kernel uses type float
template <> struct Convert_FT<float> { typedef float type; };
template <typename PointOrVectorMap>
struct GetFTFromMap
{
typedef typename Convert_FT
<typename Kernel_traits
<typename boost::property_traits
<PointOrVectorMap>::value_type>::Kernel::FT>::type type;
};
/// \endcond
/**
\ingroup PkgPointSetProcessing3IOPly
@ -118,24 +75,10 @@ namespace CGAL {
\tparam PointMap the property map used to store points.
*/
template <typename PointMap>
#ifdef DOXYGEN_RUNNING
std::tuple<PointMap,
typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3,
PLY_property<FT>, PLY_property<FT>, PLY_property<FT> >
#else
std::tuple<PointMap,
typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3,
PLY_property<typename GetFTFromMap<PointMap>::type>,
PLY_property<typename GetFTFromMap<PointMap>::type>,
PLY_property<typename GetFTFromMap<PointMap>::type> >
#endif
make_ply_point_reader(PointMap point_map)
{
return std::make_tuple (point_map, typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3(),
PLY_property<typename GetFTFromMap<PointMap>::type>("x"),
PLY_property<typename GetFTFromMap<PointMap>::type>("y"),
PLY_property<typename GetFTFromMap<PointMap>::type>("z"));
}
make_ply_point_reader(PointMap point_map);
/**
\ingroup PkgPointSetProcessing3IOPly
@ -151,573 +94,11 @@ namespace CGAL {
\tparam VectorMap the property map used to store vectors.
*/
template <typename VectorMap>
#ifdef DOXYGEN_RUNNING
std::tuple<VectorMap,
typename Kernel_traits<typename VectorMap::value_type>::Kernel::Construct_vector_3,
PLY_property<FT>, PLY_property<FT>, PLY_property<FT> >
#else
std::tuple<VectorMap,
typename Kernel_traits<typename VectorMap::value_type>::Kernel::Construct_vector_3,
PLY_property<typename GetFTFromMap<VectorMap>::type>,
PLY_property<typename GetFTFromMap<VectorMap>::type>,
PLY_property<typename GetFTFromMap<VectorMap>::type> >
#endif
make_ply_normal_reader(VectorMap normal_map)
{
return std::make_tuple (normal_map, typename Kernel_traits<typename VectorMap::value_type>::Kernel::Construct_vector_3(),
PLY_property<typename GetFTFromMap<VectorMap>::type>("nx"),
PLY_property<typename GetFTFromMap<VectorMap>::type>("ny"),
PLY_property<typename GetFTFromMap<VectorMap>::type>("nz"));
}
/// \cond SKIP_IN_MANUAL
namespace internal {
namespace PLY {
class PLY_read_number
{
protected:
std::string m_name;
std::size_t m_format;
public:
PLY_read_number (std::string name, std::size_t format)
: m_name (name), m_format (format) { }
virtual ~PLY_read_number() { }
const std::string& name () const { return m_name; }
virtual void get (std::istream& stream) const = 0;
// The two following functions prevent the stream to only extract
// ONE character (= what the types char imply) by requiring
// explicitely an integer object when reading the stream
void read_ascii (std::istream& stream, char& c) const
{
short s;
stream >> s;
c = static_cast<char>(s);
}
void read_ascii (std::istream& stream, signed char& c) const
{
short s;
stream >> s;
c = static_cast<signed char>(s);
}
void read_ascii (std::istream& stream, unsigned char& c) const
{
unsigned short s;
stream >> s;
c = static_cast<unsigned char>(s);
}
void read_ascii (std::istream& stream, float& t) const
{
stream >> iformat(t);
}
void read_ascii (std::istream& stream, double& t) const
{
stream >> iformat(t);
}
// Default template when Type is not a char type
template <typename Type>
void read_ascii (std::istream& stream, Type& t) const
{
stream >> t;
}
template <typename Type>
Type read (std::istream& stream) const
{
if (m_format == 0) // Ascii
{
Type t;
read_ascii (stream, t);
return t;
}
else // Binary (2 = little endian)
{
union
{
char uChar[sizeof (Type)];
Type type;
} buffer;
std::size_t size = sizeof (Type);
stream.read(buffer.uChar, size);
if (m_format == 2) // Big endian
{
for (std::size_t i = 0; i < size / 2; ++ i)
{
unsigned char tmp = buffer.uChar[i];
buffer.uChar[i] = buffer.uChar[size - 1 - i];
buffer.uChar[size - 1 - i] = tmp;
}
}
return buffer.type;
}
return Type();
}
};
template <typename Type>
class PLY_read_typed_number : public PLY_read_number
{
mutable Type m_buffer;
public:
PLY_read_typed_number (std::string name, std::size_t format)
: PLY_read_number (name, format)
{
}
void get (std::istream& stream) const
{
m_buffer = (this->read<Type> (stream));
}
const Type& buffer() const
{
return m_buffer;
}
};
template <typename Type>
class PLY_read_typed_list : public PLY_read_number
{
protected:
mutable std::vector<Type> m_buffer;
public:
PLY_read_typed_list (std::string name, std::size_t format)
: PLY_read_number (name, format)
{
}
virtual void get (std::istream& stream) const = 0;
const std::vector<Type>& buffer() const
{
return m_buffer;
}
};
template <typename SizeType, typename IndexType>
class PLY_read_typed_list_with_typed_size
: public PLY_read_typed_list<IndexType>
{
public:
PLY_read_typed_list_with_typed_size (std::string name, std::size_t format)
: PLY_read_typed_list<IndexType> (name, format)
{
}
void get (std::istream& stream) const
{
std::size_t size = static_cast<std::size_t>(this->template read<SizeType>(stream));
this->m_buffer.resize (size);
for (std::size_t i = 0; i < size; ++ i)
this->m_buffer[i] = this->template read<IndexType> (stream);
}
};
class PLY_element
{
std::string m_name;
std::size_t m_number;
std::vector<PLY_read_number*> m_properties;
public:
PLY_element (const std::string& name, std::size_t number)
: m_name (name), m_number (number)
{ }
PLY_element (const PLY_element& other)
: m_name (other.m_name), m_number (other.m_number), m_properties (other.m_properties)
{
const_cast<PLY_element&>(other).m_properties.clear();
}
PLY_element& operator= (const PLY_element& other)
{
m_name = other.m_name;
m_number = other.m_number;
m_properties = other.m_properties;
const_cast<PLY_element&>(other).m_properties.clear();
return *this;
}
~PLY_element()
{
for (std::size_t i = 0; i < m_properties.size(); ++ i)
delete m_properties[i];
}
const std::string& name() const { return m_name; }
std::size_t number_of_items() const { return m_number; }
std::size_t number_of_properties() const { return m_properties.size(); }
PLY_read_number* property (std::size_t idx) { return m_properties[idx]; }
void add_property (PLY_read_number* read_number)
{
m_properties.push_back (read_number);
}
template <typename Type>
bool has_property (const char* tag)
{
return has_property (tag, Type());
}
template <typename Type>
bool has_property (const char* tag, const std::vector<Type>&)
{
for (std::size_t i = 0; i < number_of_properties(); ++ i)
if (m_properties[i]->name () == tag)
return (dynamic_cast<PLY_read_typed_list<Type>*>(m_properties[i]) != NULL);
return false;
}
template <typename Type>
bool has_property (const char* tag, Type)
{
for (std::size_t i = 0; i < number_of_properties(); ++ i)
if (m_properties[i]->name () == tag)
return (dynamic_cast<PLY_read_typed_number<Type>*>(m_properties[i]) != NULL);
return false;
}
bool has_property (const char* tag, double)
{
for (std::size_t i = 0; i < number_of_properties(); ++ i)
if (m_properties[i]->name () == tag)
return (dynamic_cast<PLY_read_typed_number<double>*>(m_properties[i]) != NULL
|| dynamic_cast<PLY_read_typed_number<float>*>(m_properties[i]) != NULL);
return false;
}
template <typename Type>
void assign (Type& t, const char* tag)
{
for (std::size_t i = 0; i < number_of_properties (); ++ i)
if (m_properties[i]->name () == tag)
{
PLY_read_typed_number<Type>*
property = dynamic_cast<PLY_read_typed_number<Type>*>(m_properties[i]);
CGAL_assertion (property != NULL);
t = property->buffer();
return;
}
}
template <typename Type>
void assign (std::vector<Type>& t, const char* tag)
{
for (std::size_t i = 0; i < number_of_properties (); ++ i)
if (m_properties[i]->name () == tag)
{
PLY_read_typed_list<Type>*
property = dynamic_cast<PLY_read_typed_list<Type>*>(m_properties[i]);
CGAL_assertion (property != NULL);
t = property->buffer();
return;
}
}
void assign (double& t, const char* tag)
{
for (std::size_t i = 0; i < number_of_properties (); ++ i)
if (m_properties[i]->name () == tag)
{
PLY_read_typed_number<double>*
property_double = dynamic_cast<PLY_read_typed_number<double>*>(m_properties[i]);
if (property_double == NULL)
{
PLY_read_typed_number<float>*
property_float = dynamic_cast<PLY_read_typed_number<float>*>(m_properties[i]);
CGAL_assertion (property_float != NULL);
t = property_float->buffer();
}
else
t = property_double->buffer();
return;
}
}
};
class PLY_reader
{
std::vector<PLY_element> m_elements;
std::string m_comments;
public:
PLY_reader () { }
std::size_t number_of_elements() const { return m_elements.size(); }
PLY_element& element (std::size_t idx)
{
return m_elements[idx];
}
const std::string& comments() const { return m_comments; }
template <typename Stream>
bool init (Stream& stream)
{
std::size_t lineNumber = 0; // current line number
enum Format { ASCII = 0, BINARY_LITTLE_ENDIAN = 1, BINARY_BIG_ENDIAN = 2};
Format format = ASCII;
std::string line;
std::istringstream iss;
while (getline (stream,line))
{
iss.clear();
iss.str (line);
++ lineNumber;
// Reads file signature on first line
if (lineNumber == 1)
{
std::string signature;
if (!(iss >> signature) || (signature != "ply"))
{
// if wrong file format
std::cerr << "Error: incorrect file format line " << lineNumber << " of file" << std::endl;
return false;
}
}
// Reads format on 2nd line
else if (lineNumber == 2)
{
std::string tag, format_string, version;
if ( !(iss >> tag >> format_string >> version) )
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (format_string == "ascii") format = ASCII;
else if (format_string == "binary_little_endian") format = BINARY_LITTLE_ENDIAN;
else if (format_string == "binary_big_endian") format = BINARY_BIG_ENDIAN;
else
{
std::cerr << "Error: unknown file format \"" << format_string << "\" line " << lineNumber << std::endl;
return false;
}
}
// Comments and vertex properties
else
{
std::string keyword;
if (!(iss >> keyword))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (keyword == "property")
{
std::string type, name;
if (!(iss >> type >> name))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (type == "list") // Special case
{
std::string size_type = name;
std::string index_type;
name.clear();
if (!(iss >> index_type >> name))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
TRY_TO_GENERATE_LIST_PROPERTY ("char", "int8", boost::int8_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("uchar", "uint8", boost::uint8_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("short", "int16", boost::int16_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("ushort", "uint16", boost::uint16_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("int", "int32", boost::int32_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("uint", "uint32", boost::uint32_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("float", "float32", float);
else TRY_TO_GENERATE_LIST_PROPERTY ("double", "float64", double);
}
else
{
TRY_TO_GENERATE_PROPERTY ("char", "int8", boost::int8_t);
else TRY_TO_GENERATE_PROPERTY ("uchar", "uint8", boost::uint8_t);
else TRY_TO_GENERATE_PROPERTY ("short", "int16", boost::int16_t);
else TRY_TO_GENERATE_PROPERTY ("ushort", "uint16", boost::uint16_t);
else TRY_TO_GENERATE_PROPERTY ("int", "int32", boost::int32_t);
else TRY_TO_GENERATE_PROPERTY ("uint", "uint32", boost::uint32_t);
else TRY_TO_GENERATE_PROPERTY ("float", "float32", float);
else TRY_TO_GENERATE_PROPERTY ("double", "float64", double);
}
continue;
}
else if (keyword == "comment")
{
std::string str = iss.str();
if (str.size() > 8)
{
std::copy (str.begin() + 8, str.end(), std::back_inserter (m_comments));
m_comments += "\n";
}
}
else if (keyword == "element")
{
std::string type;
std::size_t number;
if (!(iss >> type >> number))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
m_elements.push_back (PLY_element(type, number));
}
// When end_header is reached, stop loop and begin reading points
else if (keyword == "end_header")
break;
}
}
return true;
}
~PLY_reader ()
{
}
};
template <class Reader, class T>
void get_value(Reader& r, T& v, PLY_property<T>& wrapper)
{
return r.assign(v, wrapper.name);
}
template <std::size_t N>
struct Filler
{
template <class Reader, class Value_tuple, class PLY_property_tuple>
static void fill(Reader& r, Value_tuple& values, PLY_property_tuple wrappers)
{
get_value(r, std::get<N>(values), std::get<N+2>(wrappers));
Filler<N-1>::fill(r, values, wrappers);
}
};
template<int ...>
struct seq { };
template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };
template<int ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};
template<class ValueType, class Functor, class Tuple, int ...S>
ValueType call_functor(Functor f, Tuple t, seq<S...>) {
return f(std::get<S>(t) ...);
}
template <class ValueType, class Functor, typename ... T>
ValueType call_functor(Functor f, std::tuple<T...>& t)
{
return call_functor<ValueType>(f, t, typename gens<sizeof...(T)>::type());
}
template<>
struct Filler<0>
{
template <class Reader, class Value_tuple, class PLY_property_tuple>
static void fill(Reader& r, Value_tuple& values, PLY_property_tuple wrappers)
{
get_value(r, std::get<0>(values), std::get<2>(wrappers));
}
};
template <typename OutputValueType,
typename PropertyMap,
typename Constructor,
typename ... T>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::tuple<PropertyMap, Constructor, PLY_property<T>...>&& current)
{
typedef typename PropertyMap::value_type PmapValueType;
std::tuple<T...> values;
Filler<sizeof...(T)-1>::fill(element, values, current);
PmapValueType new_value = call_functor<PmapValueType>(std::get<1>(current), values);
put (std::get<0>(current), new_element, new_value);
}
template <typename OutputValueType,
typename PropertyMap,
typename Constructor,
typename ... T,
typename NextPropertyBinder,
typename ... PropertyMapBinders>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::tuple<PropertyMap, Constructor, PLY_property<T>...>&& current,
NextPropertyBinder&& next,
PropertyMapBinders&& ... properties)
{
typedef typename PropertyMap::value_type PmapValueType;
std::tuple<T...> values;
Filler<sizeof...(T)-1>::fill(element, values, current);
PmapValueType new_value = call_functor<PmapValueType>(std::get<1>(current), values);
put (std::get<0>(current), new_element, new_value);
process_properties (element, new_element, std::forward<NextPropertyBinder>(next),
std::forward<PropertyMapBinders>(properties)...);
}
template <typename OutputValueType, typename PropertyMap, typename T>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::pair<PropertyMap, PLY_property<T> >&& current)
{
T new_value = T();
element.assign (new_value, current.second.name);
put (current.first, new_element, new_value);
}
template <typename OutputValueType, typename PropertyMap, typename T,
typename NextPropertyBinder, typename ... PropertyMapBinders>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::pair<PropertyMap, PLY_property<T> >&& current,
NextPropertyBinder&& next,
PropertyMapBinders&& ... properties)
{
T new_value = T();
element.assign (new_value, current.second.name);
put (current.first, new_element, new_value);
process_properties (element, new_element, std::forward<NextPropertyBinder>(next),
std::forward<PropertyMapBinders>(properties)...);
}
} // namespace PLY
} // namespace internal
/// \endcond
make_ply_normal_reader(VectorMap normal_map);
#endif // DOXYGEN_RUNNING
/*
\ingroup PkgPointSetProcessing3IOPly

View File

@ -27,9 +27,9 @@
#include <tuple>
#include <CGAL/IO/PLY.h>
#include <CGAL/property_map.h>
#include <CGAL/point_set_processing_assertions.h>
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/Iterator_range.h>
#include <CGAL/boost/graph/named_function_params.h>
@ -42,6 +42,7 @@
namespace CGAL {
#ifdef DOXYGEN_RUNNING // Document some parts from Stream_support here for convenience
/**
\ingroup PkgPointSetProcessing3IOPly
@ -55,21 +56,8 @@ namespace CGAL {
\tparam PointMap the property map used to store points.
*/
template <typename PointMap>
#ifdef DOXYGEN_RUNNING
std::tuple<PointMap, PLY_property<FT>, PLY_property<FT>, PLY_property<FT> >
#else
std::tuple<PointMap,
PLY_property<typename GetFTFromMap<PointMap>::type>,
PLY_property<typename GetFTFromMap<PointMap>::type>,
PLY_property<typename GetFTFromMap<PointMap>::type> >
#endif
make_ply_point_writer(PointMap point_map)
{
return std::make_tuple (point_map,
PLY_property<typename GetFTFromMap<PointMap>::type>("x"),
PLY_property<typename GetFTFromMap<PointMap>::type>("y"),
PLY_property<typename GetFTFromMap<PointMap>::type>("z"));
}
make_ply_point_writer(PointMap point_map);
/**
\ingroup PkgPointSetProcessing3IOPly
@ -84,21 +72,9 @@ namespace CGAL {
\tparam VectorMap the property map used to store vectors.
*/
template <typename VectorMap>
#ifdef DOXYGEN_RUNNING
std::tuple<VectorMap, PLY_property<FT>, PLY_property<FT>, PLY_property<FT> >
#else
std::tuple<VectorMap,
PLY_property<typename GetFTFromMap<VectorMap>::type>,
PLY_property<typename GetFTFromMap<VectorMap>::type>,
PLY_property<typename GetFTFromMap<VectorMap>::type> >
make_ply_normal_writer(VectorMap normal_map);
#endif
make_ply_normal_writer(VectorMap normal_map)
{
return std::make_tuple (normal_map,
PLY_property<typename GetFTFromMap<VectorMap>::type>("nx"),
PLY_property<typename GetFTFromMap<VectorMap>::type>("ny"),
PLY_property<typename GetFTFromMap<VectorMap>::type>("nz"));
}
/// \cond SKIP_IN_MANUAL
@ -106,219 +82,6 @@ namespace internal {
namespace PLY {
template <typename T> void property_header_type (std::ostream& stream)
{
CGAL_assertion_msg (false, "Unknown PLY type");
stream << "undefined_type";
}
template <> void property_header_type<char> (std::ostream& stream) { stream << "char"; }
template <> void property_header_type<signed char> (std::ostream& stream) { stream << "char"; }
template <> void property_header_type<unsigned char> (std::ostream& stream) { stream << "uchar"; }
template <> void property_header_type<short> (std::ostream& stream) { stream << "short"; }
template <> void property_header_type<unsigned short> (std::ostream& stream) { stream << "ushort"; }
template <> void property_header_type<int> (std::ostream& stream) { stream << "int"; }
template <> void property_header_type<unsigned int> (std::ostream& stream) { stream << "uint"; }
template <> void property_header_type<float> (std::ostream& stream) { stream << "float"; }
template <> void property_header_type<double> (std::ostream& stream) { stream << "double"; }
template <typename T>
void property_header (std::ostream& stream, const PLY_property<T>& prop)
{
stream << "property ";
property_header_type<T>(stream);
stream << " " << prop.name << std::endl;
}
template <typename T>
void property_header (std::ostream& stream, const PLY_property<std::vector<T> >& prop)
{
stream << "property list uchar ";
property_header_type<T>(stream);
stream << " " << prop.name << std::endl;
}
template <std::size_t N>
struct Properties_header
{
template <class PLY_property_tuple>
static void write(std::ostream& stream, PLY_property_tuple& wrappers)
{
Properties_header<N-1>::write(stream, wrappers);
property_header (stream, std::get<N+1>(wrappers));
}
};
template <>
struct Properties_header<0>
{
template <class PLY_property_tuple>
static void write(std::ostream& stream, PLY_property_tuple& wrappers)
{
property_header (stream, std::get<1>(wrappers));
}
};
template <typename PropertyMap,
typename ... T>
void output_property_header (std::ostream& stream,
std::tuple<PropertyMap, PLY_property<T>... >&& current)
{
Properties_header<sizeof...(T)-1>::write(stream, current);
}
template <typename PropertyMap,
typename T>
void output_property_header (std::ostream& stream,
std::pair<PropertyMap, PLY_property<T> >&& current)
{
property_header (stream, current.second);
}
template <typename PropertyMap,
typename T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_property_header (std::ostream& stream,
std::pair<PropertyMap, PLY_property<T> >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
property_header (stream, current.second);
output_property_header (stream, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
template <typename PropertyMap,
typename ... T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_property_header (std::ostream& stream,
std::tuple<PropertyMap, PLY_property<T>... >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
Properties_header<sizeof...(T)-1>::write(stream, current);
output_property_header (stream, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
template <typename ForwardIterator,
typename PropertyMap>
void property_write (std::ostream& stream, ForwardIterator it, PropertyMap map)
{
stream << CGAL::oformat(get (map, *it));
}
template <typename T>
T no_char_character (const T& t) { return t; }
int no_char_character (const char& t) { return int(t); }
int no_char_character (const signed char& t) { return int(t); }
int no_char_character (const unsigned char& t) { return int(t); }
template <typename ForwardIterator,
typename PropertyMap,
typename T>
void simple_property_write (std::ostream& stream, ForwardIterator it,
std::pair<PropertyMap, PLY_property<T> > map)
{
if (CGAL::get_mode(stream) == IO::ASCII)
stream << no_char_character(get (map.first, *it));
else
{
typename PropertyMap::value_type value = get(map.first, *it);
stream.write (reinterpret_cast<char*>(&value), sizeof(value));
}
}
template <typename ForwardIterator,
typename PropertyMap,
typename T>
void simple_property_write (std::ostream& stream, ForwardIterator it,
std::pair<PropertyMap, PLY_property<std::vector<T> > > map)
{
const typename PropertyMap::reference value = get(map.first, *it);
if (CGAL::get_mode(stream) == IO::ASCII)
{
stream << value.size();
for (std::size_t i = 0; i < value.size(); ++ i)
stream << " " << no_char_character(value[i]);
}
else
{
unsigned char size = static_cast<unsigned char>(value.size());
stream.write (reinterpret_cast<char*>(&size), sizeof(size));
for (std::size_t i = 0; i < value.size(); ++ i)
{
T t = T(value[i]);
stream.write (reinterpret_cast<char*>(&t), sizeof(t));
}
}
}
template <typename ForwardIterator,
typename PropertyMap,
typename ... T>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::tuple<PropertyMap, PLY_property<T>... >&& current)
{
property_write (stream, it, std::get<0>(current));
if (get_mode(stream) == IO::ASCII)
stream << std::endl;
}
template <typename ForwardIterator,
typename PropertyMap,
typename T>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::pair<PropertyMap, PLY_property<T> >&& current)
{
simple_property_write (stream, it, std::forward<std::pair<PropertyMap, PLY_property<T> > >(current));
if (get_mode(stream) == IO::ASCII)
stream << std::endl;
}
template <typename ForwardIterator,
typename PropertyMap,
typename T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::pair<PropertyMap, PLY_property<T> >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
simple_property_write (stream, it, current);
if (get_mode(stream) == IO::ASCII)
stream << " ";
output_properties (stream, it, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
template <typename ForwardIterator,
typename PropertyMap,
typename ... T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::tuple<PropertyMap, PLY_property<T>... >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
property_write (stream, it, std::get<0>(current));
if (get_mode(stream) == IO::ASCII)
stream << " ";
output_properties (stream, it, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
} // namespace PLY

View File

@ -12,7 +12,6 @@
#include <CGAL/IO/PLY_reader.h>
#include <CGAL/IO/PLY_writer.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include <QTime>
#include <QMessageBox>
class Polyhedron_demo_ply_plugin :
@ -38,62 +37,6 @@ public:
bool canSave(const CGAL::Three::Scene_item*);
bool save(const CGAL::Three::Scene_item*, QFileInfo fileinfo);
private:
void set_vcolors(SMesh* smesh, const std::vector<CGAL::Color>& colors)
{
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
SMesh::Property_map<vertex_descriptor, CGAL::Color> vcolors =
smesh->property_map<vertex_descriptor, CGAL::Color >("v:color").first;
bool created;
boost::tie(vcolors, created) = smesh->add_property_map<SMesh::Vertex_index,CGAL::Color>("v:color",CGAL::Color(0,0,0));
assert(colors.size()==smesh->number_of_vertices());
int color_id = 0;
for(vertex_descriptor vd : vertices(*smesh))
vcolors[vd] = colors[color_id++];
}
void set_fcolors(SMesh* smesh, const std::vector<CGAL::Color>& colors)
{
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
SMesh::Property_map<face_descriptor, CGAL::Color> fcolors =
smesh->property_map<face_descriptor, CGAL::Color >("f:color").first;
bool created;
boost::tie(fcolors, created) = smesh->add_property_map<SMesh::Face_index,CGAL::Color>("f:color",CGAL::Color(0,0,0));
assert(colors.size()==smesh->number_of_faces());
int color_id = 0;
for(face_descriptor fd : faces(*smesh))
fcolors[fd] = colors[color_id++];
}
bool set_huvs(SMesh* smesh,
std::vector<std::pair<unsigned int, unsigned int> > & hedges,
std::vector<std::pair<float, float> >& uvs)
{
QTime timer;
timer.start();
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv =
smesh->property_map<halfedge_descriptor,std::pair<float, float> >("h:uv").first;
bool created;
boost::tie(uv, created) = smesh->add_property_map<halfedge_descriptor,
std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f));
assert(hedges.size()==smesh->number_of_halfedges());
assert(uvs.size()==smesh->number_of_halfedges());
for(std::size_t id = 0; id < hedges.size(); ++id)
{
bool exists = false;
halfedge_descriptor hd;
boost::tie(hd, exists) = halfedge(
vertex_descriptor(hedges[id].first),
vertex_descriptor(hedges[id].second),
*smesh);
if(!exists)
return false;
uv[hd] = uvs[id];
}
return true;
}
};
bool Polyhedron_demo_ply_plugin::canLoad() const {
@ -146,57 +89,39 @@ Polyhedron_demo_ply_plugin::load(QFileInfo fileinfo) {
if (input_is_mesh) // Open mesh or polygon soup
{
// First try mesh
SMesh *surface_mesh = new SMesh();
std::string comments;
if (CGAL::read_ply (in, *surface_mesh, comments))
{
Scene_surface_mesh_item* sm_item = new Scene_surface_mesh_item(surface_mesh);
sm_item->setName(fileinfo.completeBaseName());
sm_item->comments() = comments;
QApplication::restoreOverrideCursor();
return sm_item;
}
in.clear();
in.seekg(0);
// else try polygon soup
std::vector<Kernel::Point_3> points;
std::vector<std::vector<std::size_t> > polygons;
std::vector<std::pair<unsigned int, unsigned int> > hedges;
std::vector<CGAL::Color> fcolors;
std::vector<CGAL::Color> vcolors;
std::vector<std::pair<float, float> > huvs;
QTime timer;
timer.start();
if (!(CGAL::read_PLY (in, points, polygons, hedges, fcolors, vcolors, huvs)))
if (!(CGAL::read_PLY (in, points, polygons, fcolors, vcolors)))
{
QApplication::restoreOverrideCursor();
return NULL;
}
if (CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh (polygons))
{
CGAL::Three::Scene_item* item = nullptr;
SMesh *surface_mesh = new SMesh();
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh (points, polygons,
*surface_mesh);
if(!(vcolors.empty()))
set_vcolors(surface_mesh, vcolors);
if(!(fcolors.empty()))
set_fcolors(surface_mesh, fcolors);
if(!huvs.empty())
{
if(!set_huvs(surface_mesh, hedges, huvs))
{
std::cerr<<"halfedge not found."<<std::endl;
return nullptr;
}
item = new Scene_textured_surface_mesh_item(surface_mesh);
item->invalidateOpenGLBuffers();
item->itemChanged();
}
else
{
item = new Scene_surface_mesh_item(surface_mesh);
}
item->setName(fileinfo.completeBaseName());
QApplication::restoreOverrideCursor();
return item;
}
else
{
Scene_polygon_soup_item* soup_item = new Scene_polygon_soup_item;
soup_item->setName(fileinfo.completeBaseName());
soup_item->load (points, polygons, fcolors, vcolors);
QApplication::restoreOverrideCursor();
return soup_item;
}
Scene_polygon_soup_item* soup_item = new Scene_polygon_soup_item;
soup_item->setName(fileinfo.completeBaseName());
soup_item->load (points, polygons, fcolors, vcolors);
QApplication::restoreOverrideCursor();
return soup_item;
}
else // Open point set
{
@ -245,7 +170,10 @@ bool Polyhedron_demo_ply_plugin::save(const CGAL::Three::Scene_item* item, QFile
return false;
std::ofstream out(fileinfo.filePath().toUtf8().data(), std::ios::binary);
out.precision (std::numeric_limits<double>::digits10 + 2);
if (choice == tr("Binary"))
CGAL::set_binary_mode(out);
else
out.precision (std::numeric_limits<double>::digits10 + 2);
// This plugin supports point sets
const Scene_points_with_normal_item* point_set_item =
@ -263,13 +191,13 @@ bool Polyhedron_demo_ply_plugin::save(const CGAL::Three::Scene_item* item, QFile
const Scene_surface_mesh_item* sm_item =
qobject_cast<const Scene_surface_mesh_item*>(item);
if (sm_item)
return CGAL::write_PLY (out, *(sm_item->polyhedron()));
return CGAL::write_ply (out, *(sm_item->polyhedron()), sm_item->comments());
// This plugin supports textured surface meshes
const Scene_textured_surface_mesh_item* stm_item =
qobject_cast<const Scene_textured_surface_mesh_item*>(item);
if (stm_item)
return CGAL::write_PLY (out, *(stm_item->textured_face_graph()));
return CGAL::write_ply (out, *(stm_item->textured_face_graph()));
return false;
}

View File

@ -150,9 +150,14 @@ public :
pen.setWidth(0);
painter->setPen(pen);
painter->setBrush(brush);
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
uv = graph->add_property_map<halfedge_descriptor,std::pair<float, float> >
("h:uv",std::make_pair(0.0f,0.0f)).first;
SMesh::Property_map<halfedge_descriptor, float> u;
SMesh::Property_map<halfedge_descriptor, float> v;
u = graph->add_property_map<halfedge_descriptor, float>
("h:u", 0.0f).first;
v = graph->add_property_map<halfedge_descriptor, float>
("h:v", 0.0f).first;
for( Component::iterator
fi = component->begin();
fi != component->end();
@ -161,11 +166,11 @@ public :
boost::graph_traits<SMesh>::face_descriptor f(*fi);
QPointF points[3];
boost::graph_traits<SMesh>::halfedge_descriptor h = halfedge(f, *graph);;
points[0] = QPointF(get(uv, h).first, -get(uv, h).second);
points[0] = QPointF(get(u, h), -get(v, h));
h = next(halfedge(f, *graph), *graph);
points[1] = QPointF(get(uv, h).first, -get(uv, h).second);
points[1] = QPointF(get(u, h), -get(v, h));
h = next(next(halfedge(f, *graph), *graph), *graph);
points[2] = QPointF(get(uv, h).first, -get(uv, h).second);
points[2] = QPointF(get(u, h), -get(v, h));
painter->drawPolygon(points,3);
}
@ -605,9 +610,12 @@ public Q_SLOTS:
{
component->insert(*bfit);
}
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
uv = sm->add_property_map<halfedge_descriptor,std::pair<float, float> >(
"h:uv",std::make_pair(0.0f,0.0f)).first;
SMesh::Property_map<halfedge_descriptor, float> umap;
SMesh::Property_map<halfedge_descriptor, float> vmap;
umap = sm->add_property_map<halfedge_descriptor, float>
("h:u", 0.0f).first;
vmap = sm->add_property_map<halfedge_descriptor, float>
("h:v", 0.0f).first;
SMesh::Halfedge_iterator it;
SMesh::Property_map<SMesh::Vertex_index, EPICK::Point_2> uv_map =
sm->property_map<SMesh::Vertex_index, EPICK::Point_2>("v:uv").first;
@ -618,7 +626,8 @@ public Q_SLOTS:
halfedge_descriptor hd(*it);
EPICK::FT u = uv_map[target(hd, *sm)].x();
EPICK::FT v = uv_map[target(hd, *sm)].y();
put(uv, *it, std::make_pair(static_cast<float>(u),static_cast<float>(v)));
put(umap, *it, static_cast<float>(u));
put(vmap, *it, static_cast<float>(v));
}
//ParamItem does not take ownership of text_mesh_bottom

View File

@ -265,8 +265,11 @@ public :
pen.setWidth(0);
painter->setPen(pen);
painter->setBrush(brush);
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
uv = graph->add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
SMesh::Property_map<halfedge_descriptor,float> u,v;
u = graph->add_property_map<halfedge_descriptor,float>("h:u", 0.0f).first;
v = graph->add_property_map<halfedge_descriptor,float>("h:v", 0.0f).first;
for( Component::iterator
fi = components->at(m_current_component).begin();
fi != components->at(m_current_component).end();
@ -276,11 +279,11 @@ uv = graph->add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv
QPointF points[3];
boost::graph_traits<Base_face_graph>::halfedge_descriptor h = halfedge(f, *graph);;
points[0] = QPointF(get(uv, h).first, get(uv, h).second);
points[0] = QPointF(get(u, h), get(v, h));
h = next(halfedge(f, *graph), *graph);
points[1] = QPointF(get(uv, h).first, get(uv, h).second);
points[1] = QPointF(get(u, h), get(v, h));
h = next(next(halfedge(f, *graph), *graph), *graph);
points[2] = QPointF(get(uv, h).first, get(uv, h).second);
points[2] = QPointF(get(u, h), get(v, h));
painter->drawPolygon(points,3);
}
}
@ -906,8 +909,13 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio
QApplication::restoreOverrideCursor();
QPointF min(FLT_MAX, FLT_MAX), max(-FLT_MAX, -FLT_MAX);
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
uv = tMesh.add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
SMesh::Property_map<halfedge_descriptor, float> umap;
SMesh::Property_map<halfedge_descriptor, float> vmap;
umap = tMesh.add_property_map<halfedge_descriptor, float>("h:u", 0.0f).first;
vmap = tMesh.add_property_map<halfedge_descriptor, float>("h:v", 0.0f).first;
tMesh.property_stats(std::cerr);
Base_face_graph::Halfedge_iterator it;
for(it = tMesh.halfedges_begin();
it != tMesh.halfedges_end();
@ -916,7 +924,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio
Seam_mesh::halfedge_descriptor hd(*it);
FT u = uv_pm[target(hd, sMesh)].x();
FT v = uv_pm[target(hd, sMesh)].y();
put(uv, *it, std::make_pair(static_cast<float>(u),static_cast<float>(v)));
put(umap, *it, static_cast<float>(u));
put(vmap, *it, static_cast<float>(v));
if(u<min.x())
min.setX(u);
if(u>max.x())

View File

@ -593,7 +593,7 @@ bool Scene_points_with_normal_item::read_ply_point_set(std::istream& stream)
d->m_points->clear();
bool ok = stream &&
CGAL::read_ply_point_set (stream, *(d->m_points), &(d->m_comments)) &&
CGAL::read_ply_point_set (stream, *(d->m_points), d->m_comments) &&
!isEmpty();
d->point_Slider->setValue(CGAL::Three::Three::getDefaultPointSize());
std::cerr << d->m_points->info();
@ -627,7 +627,7 @@ bool Scene_points_with_normal_item::write_ply_point_set(std::ostream& stream, bo
if (binary)
CGAL::set_binary_mode (stream);
CGAL::write_ply_point_set (stream, *(d->m_points), &(d->m_comments));
CGAL::write_ply_point_set (stream, *(d->m_points), d->m_comments);
return true;
}

View File

@ -211,6 +211,8 @@ struct Scene_surface_mesh_item_priv{
mutable QList<double> text_ids;
mutable std::vector<TextItem*> targeted_id;
std::string comments;
mutable bool has_fpatch_id;
mutable bool has_feature_edges;
mutable bool floated;
@ -1051,6 +1053,9 @@ Scene_surface_mesh_item::~Scene_surface_mesh_item()
SMesh* Scene_surface_mesh_item::polyhedron() { return d->smesh_; }
const SMesh* Scene_surface_mesh_item::polyhedron() const { return d->smesh_; }
std::string& Scene_surface_mesh_item::comments() { return d->comments; }
const std::string& Scene_surface_mesh_item::comments() const { return d->comments; }
void Scene_surface_mesh_item::compute_bbox()const
{
SMesh::Property_map<vertex_descriptor, Point_3> pprop = d->smesh_->points();

View File

@ -89,6 +89,10 @@ public:
Face_graph* face_graph() { return polyhedron(); }
const Face_graph* face_graph() const { return polyhedron(); }
// Gets PLY comments (empty if mesh not originated from PLY input)
std::string& comments();
const std::string& comments() const;
void invalidate_aabb_tree();
void invalidateOpenGLBuffers()Q_DECL_OVERRIDE;
void invalidate(Gl_data_names name);

View File

@ -21,8 +21,8 @@ struct Scene_textured_surface_mesh_item_priv
{
item = parent;
texture.GenerateCheckerBoard(2048,2048,128,0,0,0,250,250,255);
uv = sm->add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
umap = sm->add_property_map<halfedge_descriptor, float>("h:u", 0.0f).first;
vmap = sm->add_property_map<halfedge_descriptor, float>("h:v", 0.0f).first;
}
Scene_textured_surface_mesh_item_priv(const SMesh& p, Scene_textured_surface_mesh_item* parent)
: sm(new SMesh(p))
@ -30,14 +30,16 @@ struct Scene_textured_surface_mesh_item_priv
{
item = parent;
texture.GenerateCheckerBoard(2048,2048,128,0,0,0,250,250,255);
uv = sm->add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
umap = sm->add_property_map<halfedge_descriptor, float>("h:u", 0.0f).first;
vmap = sm->add_property_map<halfedge_descriptor, float>("h:v", 0.0f).first;
}
Scene_textured_surface_mesh_item_priv(SMesh* const p,Scene_textured_surface_mesh_item* parent)
:sm(p)
{
item = parent;
texture.GenerateCheckerBoard(2048,2048,128,0,0,0,250,250,255);
uv = sm->add_property_map<halfedge_descriptor,std::pair<float, float> >("h:uv",std::make_pair(0.0f,0.0f)).first;
umap = sm->add_property_map<halfedge_descriptor, float>("h:u", 0.0f).first;
vmap = sm->add_property_map<halfedge_descriptor, float>("h:v", 0.0f).first;
}
~Scene_textured_surface_mesh_item_priv()
@ -49,7 +51,8 @@ struct Scene_textured_surface_mesh_item_priv
SMesh* sm;
::Texture texture;
SMesh::Property_map<halfedge_descriptor,std::pair<float, float> > uv;
SMesh::Property_map<halfedge_descriptor, float> umap;
SMesh::Property_map<halfedge_descriptor, float> vmap;
//[Px][Py][Pz][Nx][Ny][Nz][u][v]
mutable std::vector<float> faces_buffer;
@ -102,8 +105,8 @@ Scene_textured_surface_mesh_item_priv::compute_normals_and_vertices(void) const
faces_buffer.push_back(n[1]);
faces_buffer.push_back(n[2]);
//uvs [2]
const float u = get(uv, *he).first;
const float v = get(uv, *he).second;
const float u = get(umap, *he);
const float v = get(vmap, *he);
faces_buffer.push_back(u);
faces_buffer.push_back(v);
}
@ -127,8 +130,8 @@ Scene_textured_surface_mesh_item_priv::compute_normals_and_vertices(void) const
edges_buffer.push_back(a.y() + offset.y);
edges_buffer.push_back(a.z() + offset.z);
//uvs [2]
float u = get(uv, halfedge(*he, *sm)).first;
float v = get(uv, halfedge(*he, *sm)).second;
float u = get(umap, halfedge(*he, *sm));
float v = get(vmap, halfedge(*he, *sm));
edges_buffer.push_back(u);
edges_buffer.push_back(v);
@ -138,8 +141,8 @@ Scene_textured_surface_mesh_item_priv::compute_normals_and_vertices(void) const
edges_buffer.push_back(b.z() + offset.z);
//uvs [2]
u = get(uv, opposite(halfedge(*he, *sm), *sm)).first;
v = get(uv, opposite(halfedge(*he, *sm), *sm)).second;
u = get(umap, opposite(halfedge(*he, *sm), *sm));
v = get(vmap, opposite(halfedge(*he, *sm), *sm));
edges_buffer.push_back(u);
edges_buffer.push_back(v);

View File

@ -20,7 +20,7 @@
#ifndef CGAL_IO_PLY_READER_H
#define CGAL_IO_PLY_READER_H
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/IO/PLY.h>
namespace CGAL{

View File

@ -20,7 +20,7 @@
#ifndef CGAL_IO_PLY_WRITER_H
#define CGAL_IO_PLY_WRITER_H
#include <CGAL/IO/write_ply_points.h>
#include <CGAL/IO/PLY.h>
namespace CGAL{

View File

@ -0,0 +1,973 @@
// Copyright (c) 2015 Geometry Factory
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0+
//
// Author(s) : Simon Giraudot
#ifndef CGAL_IO_PLY_H
#define CGAL_IO_PLY_H
#include <CGAL/Kernel_traits.h>
#include <CGAL/IO/io.h>
#include <tuple>
#include <iostream>
#include <sstream>
#include <string>
#define TRY_TO_GENERATE_PROPERTY(STD_TYPE, T_TYPE, TYPE) \
if (type == STD_TYPE || type == T_TYPE) \
m_elements.back().add_property (new PLY_read_typed_number< TYPE > (name, format))
#define TRY_TO_GENERATE_SIZED_LIST_PROPERTY(STD_SIZE_TYPE, T_SIZE_TYPE, SIZE_TYPE, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE) \
if ((size_type == STD_SIZE_TYPE || size_type == T_SIZE_TYPE) && \
(index_type == STD_INDEX_TYPE || index_type == T_INDEX_TYPE)) \
m_elements.back().add_property (new PLY_read_typed_list_with_typed_size< SIZE_TYPE , INDEX_TYPE > (name, format))
#define TRY_TO_GENERATE_LIST_PROPERTY(STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE) \
TRY_TO_GENERATE_SIZED_LIST_PROPERTY("uchar", "uint8", boost::uint8_t, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE); \
else TRY_TO_GENERATE_SIZED_LIST_PROPERTY("ushort", "uint16", boost::uint16_t, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE); \
else TRY_TO_GENERATE_SIZED_LIST_PROPERTY("uint", "uint32", boost::uint32_t, STD_INDEX_TYPE, T_INDEX_TYPE, INDEX_TYPE)
/// \cond SKIP_IN_MANUAL
namespace CGAL {
// PLY types:
// name type number of bytes
// ---------------------------------------
// char character 1
// uchar unsigned character 1
// short short integer 2
// ushort unsigned short integer 2
// int integer 4
// uint unsigned integer 4
// float single-precision float 4
// double double-precision float 8
template <typename T>
struct PLY_property
{
typedef T type;
const char* name;
PLY_property (const char* name) : name (name) { }
};
// Use a double property for all kernels...
template <typename FT> struct Convert_FT { typedef double type; };
// ...except if kernel uses type float
template <> struct Convert_FT<float> { typedef float type; };
template <typename PointOrVectorMap>
struct Get_FT_from_map
{
typedef typename Convert_FT
<typename Kernel_traits
<typename boost::property_traits
<PointOrVectorMap>::value_type>::Kernel::FT>::type type;
};
template <typename PointMap>
std::tuple<PointMap,
typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3,
PLY_property<typename Get_FT_from_map<PointMap>::type>,
PLY_property<typename Get_FT_from_map<PointMap>::type>,
PLY_property<typename Get_FT_from_map<PointMap>::type> >
make_ply_point_reader(PointMap point_map)
{
return std::make_tuple (point_map, typename Kernel_traits<typename PointMap::value_type>::Kernel::Construct_point_3(),
PLY_property<typename Get_FT_from_map<PointMap>::type>("x"),
PLY_property<typename Get_FT_from_map<PointMap>::type>("y"),
PLY_property<typename Get_FT_from_map<PointMap>::type>("z"));
}
template <typename VectorMap>
std::tuple<VectorMap,
typename Kernel_traits<typename VectorMap::value_type>::Kernel::Construct_vector_3,
PLY_property<typename Get_FT_from_map<VectorMap>::type>,
PLY_property<typename Get_FT_from_map<VectorMap>::type>,
PLY_property<typename Get_FT_from_map<VectorMap>::type> >
make_ply_normal_reader(VectorMap normal_map)
{
return std::make_tuple (normal_map, typename Kernel_traits<typename VectorMap::value_type>::Kernel::Construct_vector_3(),
PLY_property<typename Get_FT_from_map<VectorMap>::type>("nx"),
PLY_property<typename Get_FT_from_map<VectorMap>::type>("ny"),
PLY_property<typename Get_FT_from_map<VectorMap>::type>("nz"));
}
template <typename PointMap>
std::tuple<PointMap,
PLY_property<typename Get_FT_from_map<PointMap>::type>,
PLY_property<typename Get_FT_from_map<PointMap>::type>,
PLY_property<typename Get_FT_from_map<PointMap>::type> >
make_ply_point_writer(PointMap point_map)
{
return std::make_tuple (point_map,
PLY_property<typename Get_FT_from_map<PointMap>::type>("x"),
PLY_property<typename Get_FT_from_map<PointMap>::type>("y"),
PLY_property<typename Get_FT_from_map<PointMap>::type>("z"));
}
template <typename VectorMap>
std::tuple<VectorMap,
PLY_property<typename Get_FT_from_map<VectorMap>::type>,
PLY_property<typename Get_FT_from_map<VectorMap>::type>,
PLY_property<typename Get_FT_from_map<VectorMap>::type> >
make_ply_normal_writer(VectorMap normal_map)
{
return std::make_tuple (normal_map,
PLY_property<typename Get_FT_from_map<VectorMap>::type>("nx"),
PLY_property<typename Get_FT_from_map<VectorMap>::type>("ny"),
PLY_property<typename Get_FT_from_map<VectorMap>::type>("nz"));
}
namespace internal {
namespace PLY {
class PLY_read_number
{
protected:
std::string m_name;
std::size_t m_format;
public:
PLY_read_number (std::string name, std::size_t format)
: m_name (name), m_format (format) { }
virtual ~PLY_read_number() { }
const std::string& name () const { return m_name; }
virtual void get (std::istream& stream) const = 0;
// The two following functions prevent the stream to only extract
// ONE character (= what the types char imply) by requiring
// explicitely an integer object when reading the stream
void read_ascii (std::istream& stream, char& c) const
{
short s;
stream >> s;
c = static_cast<char>(s);
}
void read_ascii (std::istream& stream, signed char& c) const
{
short s;
stream >> s;
c = static_cast<signed char>(s);
}
void read_ascii (std::istream& stream, unsigned char& c) const
{
unsigned short s;
stream >> s;
c = static_cast<unsigned char>(s);
}
void read_ascii (std::istream& stream, float& t) const
{
stream >> iformat(t);
}
void read_ascii (std::istream& stream, double& t) const
{
stream >> iformat(t);
}
// Default template when Type is not a char type
template <typename Type>
void read_ascii (std::istream& stream, Type& t) const
{
stream >> t;
}
template <typename Type>
Type read (std::istream& stream) const
{
if (m_format == 0) // Ascii
{
Type t;
read_ascii (stream, t);
return t;
}
else // Binary (2 = little endian)
{
union
{
char uChar[sizeof (Type)];
Type type;
} buffer;
std::size_t size = sizeof (Type);
stream.read(buffer.uChar, size);
if (m_format == 2) // Big endian
{
for (std::size_t i = 0; i < size / 2; ++ i)
{
unsigned char tmp = buffer.uChar[i];
buffer.uChar[i] = buffer.uChar[size - 1 - i];
buffer.uChar[size - 1 - i] = tmp;
}
}
return buffer.type;
}
return Type();
}
};
template <typename Type>
class PLY_read_typed_number : public PLY_read_number
{
mutable Type m_buffer;
public:
PLY_read_typed_number (std::string name, std::size_t format)
: PLY_read_number (name, format)
{
}
void get (std::istream& stream) const
{
m_buffer = (this->read<Type> (stream));
}
const Type& buffer() const
{
return m_buffer;
}
};
template <typename Type>
class PLY_read_typed_list : public PLY_read_number
{
protected:
mutable std::vector<Type> m_buffer;
public:
PLY_read_typed_list (std::string name, std::size_t format)
: PLY_read_number (name, format)
{
}
virtual void get (std::istream& stream) const = 0;
const std::vector<Type>& buffer() const
{
return m_buffer;
}
};
template <typename SizeType, typename IndexType>
class PLY_read_typed_list_with_typed_size
: public PLY_read_typed_list<IndexType>
{
public:
PLY_read_typed_list_with_typed_size (std::string name, std::size_t format)
: PLY_read_typed_list<IndexType> (name, format)
{
}
void get (std::istream& stream) const
{
std::size_t size = static_cast<std::size_t>(this->template read<SizeType>(stream));
this->m_buffer.resize (size);
for (std::size_t i = 0; i < size; ++ i)
this->m_buffer[i] = this->template read<IndexType> (stream);
}
};
class PLY_element
{
std::string m_name;
std::size_t m_number;
std::vector<PLY_read_number*> m_properties;
public:
PLY_element (const std::string& name, std::size_t number)
: m_name (name), m_number (number)
{ }
PLY_element (const PLY_element& other)
: m_name (other.m_name), m_number (other.m_number), m_properties (other.m_properties)
{
const_cast<PLY_element&>(other).m_properties.clear();
}
PLY_element& operator= (const PLY_element& other)
{
m_name = other.m_name;
m_number = other.m_number;
m_properties = other.m_properties;
const_cast<PLY_element&>(other).m_properties.clear();
return *this;
}
~PLY_element()
{
for (std::size_t i = 0; i < m_properties.size(); ++ i)
delete m_properties[i];
}
const std::string& name() const { return m_name; }
std::size_t number_of_items() const { return m_number; }
std::size_t number_of_properties() const { return m_properties.size(); }
PLY_read_number* property (std::size_t idx) { return m_properties[idx]; }
void add_property (PLY_read_number* read_number)
{
m_properties.push_back (read_number);
}
template <typename Type>
bool has_property (const char* tag)
{
return has_property (tag, Type());
}
template <typename Type>
bool has_property (const char* tag, const std::vector<Type>&)
{
for (std::size_t i = 0; i < number_of_properties(); ++ i)
if (m_properties[i]->name () == tag)
return (dynamic_cast<PLY_read_typed_list<Type>*>(m_properties[i]) != NULL);
return false;
}
template <typename Type>
bool has_property (const char* tag, Type)
{
for (std::size_t i = 0; i < number_of_properties(); ++ i)
if (m_properties[i]->name () == tag)
return (dynamic_cast<PLY_read_typed_number<Type>*>(m_properties[i]) != NULL);
return false;
}
bool has_property (const char* tag, double)
{
for (std::size_t i = 0; i < number_of_properties(); ++ i)
if (m_properties[i]->name () == tag)
return (dynamic_cast<PLY_read_typed_number<double>*>(m_properties[i]) != NULL
|| dynamic_cast<PLY_read_typed_number<float>*>(m_properties[i]) != NULL);
return false;
}
template <typename Type>
void assign (Type& t, const char* tag)
{
for (std::size_t i = 0; i < number_of_properties (); ++ i)
if (m_properties[i]->name () == tag)
{
PLY_read_typed_number<Type>*
property = dynamic_cast<PLY_read_typed_number<Type>*>(m_properties[i]);
CGAL_assertion (property != NULL);
t = property->buffer();
return;
}
}
template <typename Type>
void assign (std::vector<Type>& t, const char* tag)
{
for (std::size_t i = 0; i < number_of_properties (); ++ i)
if (m_properties[i]->name () == tag)
{
PLY_read_typed_list<Type>*
property = dynamic_cast<PLY_read_typed_list<Type>*>(m_properties[i]);
CGAL_assertion (property != NULL);
t = property->buffer();
return;
}
}
void assign (double& t, const char* tag)
{
for (std::size_t i = 0; i < number_of_properties (); ++ i)
if (m_properties[i]->name () == tag)
{
PLY_read_typed_number<double>*
property_double = dynamic_cast<PLY_read_typed_number<double>*>(m_properties[i]);
if (property_double == NULL)
{
PLY_read_typed_number<float>*
property_float = dynamic_cast<PLY_read_typed_number<float>*>(m_properties[i]);
CGAL_assertion (property_float != NULL);
t = property_float->buffer();
}
else
t = property_double->buffer();
return;
}
}
};
class PLY_reader
{
std::vector<PLY_element> m_elements;
std::string m_comments;
public:
PLY_reader () { }
std::size_t number_of_elements() const { return m_elements.size(); }
PLY_element& element (std::size_t idx)
{
return m_elements[idx];
}
const std::string& comments() const { return m_comments; }
template <typename Stream>
bool init (Stream& stream)
{
std::size_t lineNumber = 0; // current line number
enum Format { ASCII = 0, BINARY_LITTLE_ENDIAN = 1, BINARY_BIG_ENDIAN = 2};
Format format = ASCII;
std::string line;
std::istringstream iss;
while (getline (stream,line))
{
iss.clear();
iss.str (line);
++ lineNumber;
// Reads file signature on first line
if (lineNumber == 1)
{
std::string signature;
if (!(iss >> signature) || (signature != "ply"))
{
// if wrong file format
std::cerr << "Error: incorrect file format line " << lineNumber << " of file" << std::endl;
return false;
}
}
// Reads format on 2nd line
else if (lineNumber == 2)
{
std::string tag, format_string, version;
if ( !(iss >> tag >> format_string >> version) )
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (format_string == "ascii") format = ASCII;
else if (format_string == "binary_little_endian") format = BINARY_LITTLE_ENDIAN;
else if (format_string == "binary_big_endian") format = BINARY_BIG_ENDIAN;
else
{
std::cerr << "Error: unknown file format \"" << format_string << "\" line " << lineNumber << std::endl;
return false;
}
}
// Comments and vertex properties
else
{
std::string keyword;
if (!(iss >> keyword))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (keyword == "property")
{
std::string type, name;
if (!(iss >> type >> name))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (type == "list") // Special case
{
std::string size_type = name;
std::string index_type;
name.clear();
if (!(iss >> index_type >> name))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
TRY_TO_GENERATE_LIST_PROPERTY ("char", "int8", boost::int8_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("uchar", "uint8", boost::uint8_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("short", "int16", boost::int16_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("ushort", "uint16", boost::uint16_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("int", "int32", boost::int32_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("uint", "uint32", boost::uint32_t);
else TRY_TO_GENERATE_LIST_PROPERTY ("float", "float32", float);
else TRY_TO_GENERATE_LIST_PROPERTY ("double", "float64", double);
}
else
{
TRY_TO_GENERATE_PROPERTY ("char", "int8", boost::int8_t);
else TRY_TO_GENERATE_PROPERTY ("uchar", "uint8", boost::uint8_t);
else TRY_TO_GENERATE_PROPERTY ("short", "int16", boost::int16_t);
else TRY_TO_GENERATE_PROPERTY ("ushort", "uint16", boost::uint16_t);
else TRY_TO_GENERATE_PROPERTY ("int", "int32", boost::int32_t);
else TRY_TO_GENERATE_PROPERTY ("uint", "uint32", boost::uint32_t);
else TRY_TO_GENERATE_PROPERTY ("float", "float32", float);
else TRY_TO_GENERATE_PROPERTY ("double", "float64", double);
}
continue;
}
else if (keyword == "comment")
{
std::string str = iss.str();
if (str.size() > 8)
{
std::copy (str.begin() + 8, str.end(), std::back_inserter (m_comments));
m_comments += "\n";
}
}
else if (keyword == "element")
{
std::string type;
std::size_t number;
if (!(iss >> type >> number))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
m_elements.push_back (PLY_element(type, number));
}
// When end_header is reached, stop loop and begin reading points
else if (keyword == "end_header")
break;
}
}
return true;
}
~PLY_reader ()
{
}
};
template <class Reader, class T>
void get_value(Reader& r, T& v, PLY_property<T>& wrapper)
{
return r.assign(v, wrapper.name);
}
template <std::size_t N>
struct Filler
{
template <class Reader, class Value_tuple, class PLY_property_tuple>
static void fill(Reader& r, Value_tuple& values, PLY_property_tuple wrappers)
{
get_value(r, std::get<N>(values), std::get<N+2>(wrappers));
Filler<N-1>::fill(r, values, wrappers);
}
};
template<int ...>
struct seq { };
template<int N, int ...S>
struct gens : gens<N-1, N-1, S...> { };
template<int ...S>
struct gens<0, S...> {
typedef seq<S...> type;
};
template<class ValueType, class Functor, class Tuple, int ...S>
ValueType call_functor(Functor f, Tuple t, seq<S...>) {
return f(std::get<S>(t) ...);
}
template <class ValueType, class Functor, typename ... T>
ValueType call_functor(Functor f, std::tuple<T...>& t)
{
return call_functor<ValueType>(f, t, typename gens<sizeof...(T)>::type());
}
template<>
struct Filler<0>
{
template <class Reader, class Value_tuple, class PLY_property_tuple>
static void fill(Reader& r, Value_tuple& values, PLY_property_tuple wrappers)
{
get_value(r, std::get<0>(values), std::get<2>(wrappers));
}
};
template <typename OutputValueType,
typename PropertyMap,
typename Constructor,
typename ... T>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::tuple<PropertyMap, Constructor, PLY_property<T>...>&& current)
{
typedef typename PropertyMap::value_type PmapValueType;
std::tuple<T...> values;
Filler<sizeof...(T)-1>::fill(element, values, current);
PmapValueType new_value = call_functor<PmapValueType>(std::get<1>(current), values);
put (std::get<0>(current), new_element, new_value);
}
template <typename OutputValueType,
typename PropertyMap,
typename Constructor,
typename ... T,
typename NextPropertyBinder,
typename ... PropertyMapBinders>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::tuple<PropertyMap, Constructor, PLY_property<T>...>&& current,
NextPropertyBinder&& next,
PropertyMapBinders&& ... properties)
{
typedef typename PropertyMap::value_type PmapValueType;
std::tuple<T...> values;
Filler<sizeof...(T)-1>::fill(element, values, current);
PmapValueType new_value = call_functor<PmapValueType>(std::get<1>(current), values);
put (std::get<0>(current), new_element, new_value);
process_properties (element, new_element, std::forward<NextPropertyBinder>(next),
std::forward<PropertyMapBinders>(properties)...);
}
template <typename OutputValueType, typename PropertyMap, typename T>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::pair<PropertyMap, PLY_property<T> >&& current)
{
T new_value = T();
element.assign (new_value, current.second.name);
put (current.first, new_element, new_value);
}
template <typename OutputValueType, typename PropertyMap, typename T,
typename NextPropertyBinder, typename ... PropertyMapBinders>
void process_properties (PLY_element& element, OutputValueType& new_element,
std::pair<PropertyMap, PLY_property<T> >&& current,
NextPropertyBinder&& next,
PropertyMapBinders&& ... properties)
{
T new_value = T();
element.assign (new_value, current.second.name);
put (current.first, new_element, new_value);
process_properties (element, new_element, std::forward<NextPropertyBinder>(next),
std::forward<PropertyMapBinders>(properties)...);
}
template <typename T> inline void property_header_type (std::ostream& stream)
{
CGAL_assertion_msg (false, "Unknown PLY type");
stream << "undefined_type";
}
template <> inline void property_header_type<char> (std::ostream& stream) { stream << "char"; }
template <> inline void property_header_type<signed char> (std::ostream& stream) { stream << "char"; }
template <> inline void property_header_type<unsigned char> (std::ostream& stream) { stream << "uchar"; }
template <> inline void property_header_type<short> (std::ostream& stream) { stream << "short"; }
template <> inline void property_header_type<unsigned short> (std::ostream& stream) { stream << "ushort"; }
template <> inline void property_header_type<int> (std::ostream& stream) { stream << "int"; }
template <> inline void property_header_type<unsigned int> (std::ostream& stream) { stream << "uint"; }
template <> inline void property_header_type<float> (std::ostream& stream) { stream << "float"; }
template <> inline void property_header_type<double> (std::ostream& stream) { stream << "double"; }
template <typename T>
void property_header (std::ostream& stream, const PLY_property<T>& prop)
{
stream << "property ";
property_header_type<T>(stream);
stream << " " << prop.name << std::endl;
}
template <typename T>
void property_header (std::ostream& stream, const PLY_property<std::vector<T> >& prop)
{
stream << "property list uchar ";
property_header_type<T>(stream);
stream << " " << prop.name << std::endl;
}
template <std::size_t N>
struct Properties_header
{
template <class PLY_property_tuple>
static void write(std::ostream& stream, PLY_property_tuple& wrappers)
{
Properties_header<N-1>::write(stream, wrappers);
property_header (stream, std::get<N+1>(wrappers));
}
};
template <>
struct Properties_header<0>
{
template <class PLY_property_tuple>
static void write(std::ostream& stream, PLY_property_tuple& wrappers)
{
property_header (stream, std::get<1>(wrappers));
}
};
template <typename PropertyMap,
typename ... T>
void output_property_header (std::ostream& stream,
std::tuple<PropertyMap, PLY_property<T>... >&& current)
{
Properties_header<sizeof...(T)-1>::write(stream, current);
}
template <typename PropertyMap,
typename T>
void output_property_header (std::ostream& stream,
std::pair<PropertyMap, PLY_property<T> >&& current)
{
property_header (stream, current.second);
}
template <typename PropertyMap,
typename T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_property_header (std::ostream& stream,
std::pair<PropertyMap, PLY_property<T> >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
property_header (stream, current.second);
output_property_header (stream, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
template <typename PropertyMap,
typename ... T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_property_header (std::ostream& stream,
std::tuple<PropertyMap, PLY_property<T>... >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
Properties_header<sizeof...(T)-1>::write(stream, current);
output_property_header (stream, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
template <typename ForwardIterator,
typename PropertyMap>
void property_write (std::ostream& stream, ForwardIterator it, PropertyMap map)
{
stream << CGAL::oformat(get (map, *it));
}
template <typename T>
inline T no_char_character (const T& t) { return t; }
inline int no_char_character (const char& t) { return int(t); }
inline int no_char_character (const signed char& t) { return int(t); }
inline int no_char_character (const unsigned char& t) { return int(t); }
template <typename ForwardIterator,
typename PropertyMap,
typename T>
void simple_property_write (std::ostream& stream, ForwardIterator it,
std::pair<PropertyMap, PLY_property<T> > map)
{
if (CGAL::get_mode(stream) == IO::ASCII)
stream << no_char_character(get (map.first, *it));
else
{
typename PropertyMap::value_type value = get(map.first, *it);
stream.write (reinterpret_cast<char*>(&value), sizeof(value));
}
}
template <typename ForwardIterator,
typename PropertyMap,
typename T>
void simple_property_write (std::ostream& stream, ForwardIterator it,
std::pair<PropertyMap, PLY_property<std::vector<T> > > map)
{
const typename PropertyMap::reference value = get(map.first, *it);
if (CGAL::get_mode(stream) == IO::ASCII)
{
stream << value.size();
for (std::size_t i = 0; i < value.size(); ++ i)
stream << " " << no_char_character(value[i]);
}
else
{
unsigned char size = static_cast<unsigned char>(value.size());
stream.write (reinterpret_cast<char*>(&size), sizeof(size));
for (std::size_t i = 0; i < value.size(); ++ i)
{
T t = T(value[i]);
stream.write (reinterpret_cast<char*>(&t), sizeof(t));
}
}
}
template <typename ForwardIterator,
typename PropertyMap,
typename ... T>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::tuple<PropertyMap, PLY_property<T>... >&& current)
{
property_write (stream, it, std::get<0>(current));
if (get_mode(stream) == IO::ASCII)
stream << std::endl;
}
template <typename ForwardIterator,
typename PropertyMap,
typename T>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::pair<PropertyMap, PLY_property<T> >&& current)
{
simple_property_write (stream, it, std::forward<std::pair<PropertyMap, PLY_property<T> > >(current));
if (get_mode(stream) == IO::ASCII)
stream << std::endl;
}
template <typename ForwardIterator,
typename PropertyMap,
typename T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::pair<PropertyMap, PLY_property<T> >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
simple_property_write (stream, it, current);
if (get_mode(stream) == IO::ASCII)
stream << " ";
output_properties (stream, it, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
template <typename ForwardIterator,
typename PropertyMap,
typename ... T,
typename NextPropertyHandler,
typename ... PropertyHandler>
void output_properties (std::ostream& stream,
ForwardIterator it,
std::tuple<PropertyMap, PLY_property<T>... >&& current,
NextPropertyHandler&& next,
PropertyHandler&& ... properties)
{
property_write (stream, it, std::get<0>(current));
if (get_mode(stream) == IO::ASCII)
stream << " ";
output_properties (stream, it, std::forward<NextPropertyHandler>(next),
std::forward<PropertyHandler>(properties)...);
}
// Printer classes used by Point_set_3 and Surface_mesh (translate a
// property map to a PLY property)
template <typename Index>
class Abstract_property_printer
{
public:
virtual ~Abstract_property_printer() { }
virtual void print (std::ostream& stream, const Index& index) = 0;
};
template <typename Index, typename PropertyMap>
class Property_printer : public Abstract_property_printer<Index>
{
PropertyMap m_pmap;
public:
Property_printer (const PropertyMap& pmap) : m_pmap (pmap)
{
}
virtual void print(std::ostream& stream, const Index& index)
{
stream << get(m_pmap, index);
}
};
template <typename Index, typename PropertyMap,
typename Type = typename PropertyMap::value_type>
class Simple_property_printer : public Abstract_property_printer<Index>
{
PropertyMap m_pmap;
public:
Simple_property_printer (const PropertyMap& pmap) : m_pmap (pmap)
{
}
virtual void print(std::ostream& stream, const Index& index)
{
if (get_mode(stream) == IO::ASCII)
stream << get(m_pmap, index);
else
{
Type t = Type(get (m_pmap, index));
stream.write (reinterpret_cast<char*>(&t), sizeof(t));
}
}
};
template <typename Index, typename PropertyMap>
class Char_property_printer : public Abstract_property_printer<Index>
{
typedef typename PropertyMap::value_type Type;
PropertyMap m_pmap;
public:
Char_property_printer (const PropertyMap& pmap) : m_pmap (pmap)
{
}
virtual void print(std::ostream& stream, const Index& index)
{
if (get_mode(stream) == IO::ASCII)
stream << int(get(m_pmap, index));
else
{
Type t = get (m_pmap, index);
stream.write (reinterpret_cast<char*>(&t), sizeof(t));
}
}
};
} // namespace PLY
} // namespace internal
} // namespace CGAL
#endif // CGAL_IO_PLY_H

View File

@ -0,0 +1,729 @@
// Copyright (c) 2018 GeometryFactory Sarl (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Simon Giraudot
#ifndef CGAL_SURFACE_MESH_IO_PLY
#define CGAL_SURFACE_MESH_IO_PLY
#include <CGAL/IO/PLY.h>
namespace CGAL {
namespace internal {
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
namespace PLY {
template <typename Point>
class Surface_mesh_filler
{
public:
typedef typename Kernel_traits<Point>::Kernel Kernel;
typedef typename Kernel::Vector_3 Vector;
typedef CGAL::Surface_mesh<Point> Surface_mesh;
typedef typename Surface_mesh::size_type size_type;
typedef typename Surface_mesh::Vertex_index Vertex_index;
typedef typename Surface_mesh::Face_index Face_index;
typedef typename Surface_mesh::Edge_index Edge_index;
typedef typename Surface_mesh::Halfedge_index Halfedge_index;
private:
struct Abstract_ply_property_to_surface_mesh_property
{
virtual ~Abstract_ply_property_to_surface_mesh_property() { }
virtual void assign (PLY_element& element, size_type index) = 0;
};
template <typename Simplex, typename Type>
class PLY_property_to_surface_mesh_property : public Abstract_ply_property_to_surface_mesh_property
{
typedef typename Surface_mesh::template Property_map<Simplex, Type> Map;
Map m_map;
std::string m_name;
public:
PLY_property_to_surface_mesh_property (Surface_mesh& sm, const std::string& name)
: m_name (name)
{
m_map = sm.template add_property_map<Simplex, Type>(prefix(Simplex()) + name).first;
}
virtual void assign (PLY_element& element, size_type index)
{
Type t{};
element.assign (t, m_name.c_str());
put(m_map, Simplex(index), t);
}
std::string prefix(Vertex_index) const { return "v:"; }
std::string prefix(Face_index) const { return "f:"; }
std::string prefix(Edge_index) const { return "e:"; }
std::string prefix(Halfedge_index) const { return "h:"; }
};
Surface_mesh& m_mesh;
std::vector<Vertex_index> m_map_v2v;
bool m_use_floats;
int m_normals;
typename Surface_mesh::template Property_map<Vertex_index, Vector> m_normal_map;
int m_vcolors;
typename Surface_mesh::template Property_map<Vertex_index, CGAL::Color> m_vcolor_map;
int m_fcolors;
typename Surface_mesh::template Property_map<Face_index, CGAL::Color> m_fcolor_map;
bool m_use_int32_t;
std::string m_index_tag;
std::vector<Abstract_ply_property_to_surface_mesh_property*> m_vertex_properties;
std::vector<Abstract_ply_property_to_surface_mesh_property*> m_face_properties;
std::vector<Abstract_ply_property_to_surface_mesh_property*> m_edge_properties;
std::vector<Abstract_ply_property_to_surface_mesh_property*> m_halfedge_properties;
public:
Surface_mesh_filler (Surface_mesh& mesh)
: m_mesh (mesh), m_use_floats (false), m_normals(0), m_vcolors(0), m_fcolors(0)
{ }
~Surface_mesh_filler()
{
for (std::size_t i = 0; i < m_vertex_properties.size(); ++ i)
delete m_vertex_properties[i];
for (std::size_t i = 0; i < m_face_properties.size(); ++ i)
delete m_face_properties[i];
for (std::size_t i = 0; i < m_edge_properties.size(); ++ i)
delete m_edge_properties[i];
for (std::size_t i = 0; i < m_halfedge_properties.size(); ++ i)
delete m_halfedge_properties[i];
}
bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Vertex_index)
{
const std::string& name = property->name();
if (name == "x" ||
name == "y" ||
name == "z")
{
if (dynamic_cast<PLY_read_typed_number<float>*>(property))
m_use_floats = true;
return true;
}
if (name == "nx" ||
name == "ny" ||
name == "nz")
{
++ m_normals;
if (m_normals == 3)
m_normal_map = m_mesh.template add_property_map<Vertex_index, Vector>("v:normal").first;
return true;
}
if (name == "red" ||
name == "green" ||
name == "blue")
{
++ m_vcolors;
if (m_vcolors == 3)
m_vcolor_map = m_mesh.template add_property_map<Vertex_index, CGAL::Color>("v:color").first;
return true;
}
return false;
}
bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Face_index)
{
const std::string& name = property->name();
if (name == "vertex_indices" || name == "vertex_index")
{
CGAL_assertion (dynamic_cast<PLY_read_typed_list<boost::int32_t>*>(property)
|| dynamic_cast<PLY_read_typed_list<boost::uint32_t>*>(property));
m_index_tag = name;
m_use_int32_t = dynamic_cast<PLY_read_typed_list<boost::int32_t>*>(property);
return true;
}
if (name == "red" ||
name == "green" ||
name == "blue")
{
++ m_fcolors;
if (m_fcolors == 3)
m_fcolor_map = m_mesh.template add_property_map<Face_index, CGAL::Color>("f:color").first;
return true;
}
return false;
}
bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Edge_index)
{
const std::string& name = property->name();
if (name == "v0" || name == "v1")
return true;
return false;
}
bool has_simplex_specific_property (internal::PLY::PLY_read_number* property, Halfedge_index)
{
const std::string& name = property->name();
if (name == "source" || name == "target")
return true;
return false;
}
void instantiate_vertex_properties (PLY_element& element)
{
m_map_v2v.reserve(element.number_of_items());
instantiate_properties<Vertex_index> (element, m_vertex_properties);
}
void instantiate_face_properties (PLY_element& element)
{
instantiate_properties<Face_index> (element, m_face_properties);
}
void instantiate_edge_properties (PLY_element& element)
{
instantiate_properties<Edge_index> (element, m_edge_properties);
}
void instantiate_halfedge_properties (PLY_element& element)
{
instantiate_properties<Halfedge_index> (element, m_halfedge_properties);
}
template <typename Simplex>
void instantiate_properties (PLY_element& element,
std::vector<Abstract_ply_property_to_surface_mesh_property*>& properties)
{
for (std::size_t j = 0; j < element.number_of_properties(); ++ j)
{
internal::PLY::PLY_read_number* property = element.property(j);
if (has_simplex_specific_property (property, Simplex()))
continue;
const std::string& name = property->name();
if (dynamic_cast<PLY_read_typed_number<boost::int8_t>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, boost::int8_t>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<boost::uint8_t>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, boost::uint8_t>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<boost::int16_t>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, boost::int16_t>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<boost::uint16_t>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, boost::uint16_t>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<boost::int32_t>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, boost::int32_t>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<boost::uint32_t>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, boost::uint32_t>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<float>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, float>(m_mesh,
name));
}
else if (dynamic_cast<PLY_read_typed_number<double>*>(property))
{
properties.push_back
(new PLY_property_to_surface_mesh_property<Simplex, double>(m_mesh,
name));
}
}
}
void process_vertex_line (PLY_element& element)
{
Vertex_index vi;
if (m_use_floats)
process_line<float>(element, vi);
else
process_line<double>(element, vi);
for (std::size_t i = 0; i < m_vertex_properties.size(); ++ i)
m_vertex_properties[i]->assign (element, vi);
}
template <typename FT>
void process_line (PLY_element& element, Vertex_index& vi)
{
FT x = (FT)0.,y = (FT)0., z = (FT)0.,
nx = (FT)0., ny = (FT)0., nz = (FT)0.;
element.assign (x, "x");
element.assign (y, "y");
element.assign (z, "z");
Point point (x, y, z);
vi = m_mesh.add_vertex(point);
m_map_v2v.push_back(vi);
if (m_normals == 3)
{
element.assign (nx, "nx");
element.assign (ny, "ny");
element.assign (nz, "nz");
Vector normal (nx, ny, nz);
m_normal_map[vi] = normal;
}
if (m_vcolors == 3)
{
unsigned char r, g, b;
element.assign (r, "red");
element.assign (g, "green");
element.assign (b, "blue");
m_vcolor_map[vi] = CGAL::Color (r, g, b);
}
}
bool process_face_line (PLY_element& element)
{
Face_index fi = m_mesh.null_face();
if (m_use_int32_t)
process_line<boost::int32_t>(element, fi);
else
process_line<boost::uint32_t>(element, fi);
if (fi == Surface_mesh::null_face())
return false;
for (std::size_t i = 0; i < m_face_properties.size(); ++ i)
m_face_properties[i]->assign (element, fi);
return true;
}
template <typename IntType>
void process_line (PLY_element& element, Face_index& fi)
{
std::vector<IntType> indices;
element.assign (indices, m_index_tag.c_str());
std::vector<Vertex_index> vertices;
vertices.reserve(indices.size());
for (std::size_t i = 0; i < indices.size(); ++ i)
vertices.push_back (m_map_v2v[std::size_t(indices[i])]);
fi = m_mesh.add_face(vertices);
if (fi == m_mesh.null_face())
return;
if (m_fcolors == 3)
{
unsigned char r, g, b;
element.assign (r, "red");
element.assign (g, "green");
element.assign (b, "blue");
m_fcolor_map[fi] = CGAL::Color (r, g, b);
}
}
bool process_edge_line (PLY_element& element)
{
Edge_index ei = m_mesh.null_edge();
if (m_use_int32_t)
process_line<boost::int32_t>(element, ei);
else
process_line<boost::uint32_t>(element, ei);
if (ei == Surface_mesh::null_edge())
return false;
for (std::size_t i = 0; i < m_edge_properties.size(); ++ i)
m_edge_properties[i]->assign (element, ei);
return true;
}
template <typename IntType>
void process_line (PLY_element& element, Edge_index& ei)
{
IntType v0, v1;
element.assign (v0, "v0");
element.assign (v1, "v1");
Halfedge_index hi = m_mesh.halfedge(m_map_v2v[std::size_t(v0)],
m_map_v2v[std::size_t(v1)]);
if (hi == m_mesh.null_halfedge())
return;
ei = m_mesh.edge (hi);
}
bool process_halfedge_line (PLY_element& element)
{
Halfedge_index hi = m_mesh.null_halfedge();
if (m_use_int32_t)
process_line<boost::int32_t>(element, hi);
else
process_line<boost::uint32_t>(element, hi);
if (hi == Surface_mesh::null_halfedge())
return false;
for (std::size_t i = 0; i < m_halfedge_properties.size(); ++ i)
m_halfedge_properties[i]->assign (element, hi);
return true;
}
template <typename IntType>
void process_line (PLY_element& element, Halfedge_index& hi)
{
IntType source, target;
element.assign (source, "source");
element.assign (target, "target");
hi = m_mesh.halfedge(m_map_v2v[std::size_t(source)], m_map_v2v[std::size_t(target)]);
}
};
template <typename Point>
bool fill_simplex_specific_header
(std::ostream& os, const Surface_mesh<Point>& sm,
std::vector<Abstract_property_printer<typename Surface_mesh<Point>::Vertex_index>*>& printers,
const std::string& prop)
{
typedef Surface_mesh<Point> SMesh;
typedef typename SMesh::Vertex_index VIndex;
typedef typename Kernel_traits<Point>::Kernel Kernel;
typedef typename Kernel::FT FT;
typedef typename Kernel::Vector_3 Vector;
typedef typename SMesh::template Property_map<VIndex, Point> Point_map;
typedef typename SMesh::template Property_map<VIndex, Vector> Vector_map;
typedef typename SMesh::template Property_map<VIndex, Color> Vcolor_map;
if (prop == "v:connectivity" ||
prop == "v:removed")
return true;
if (prop == "v:point")
{
if (boost::is_same<FT, float>::value)
{
os << "property float x" << std::endl
<< "property float y" << std::endl
<< "property float z" << std::endl;
}
else
{
os << "property double x" << std::endl
<< "property double y" << std::endl
<< "property double z" << std::endl;
}
printers.push_back (new Property_printer<VIndex,Point_map>(sm.points()));
return true;
}
bool okay = false;
if (prop == "v:normal")
{
Vector_map pmap;
boost::tie (pmap, okay) = sm.template property_map<VIndex,Vector>(prop);
if (okay)
{
if (boost::is_same<FT, float>::value)
{
os << "property float nx" << std::endl
<< "property float ny" << std::endl
<< "property float nz" << std::endl;
}
else
{
os << "property double nx" << std::endl
<< "property double ny" << std::endl
<< "property double nz" << std::endl;
}
printers.push_back (new Property_printer<VIndex,Vector_map>(pmap));
return true;
}
}
if (prop == "v:color")
{
Vcolor_map pmap;
boost::tie (pmap, okay) = sm.template property_map<VIndex,Color>(prop);
if (okay)
{
os << "property uchar red" << std::endl
<< "property uchar green" << std::endl
<< "property uchar blue" << std::endl
<< "property uchar alpha" << std::endl;
printers.push_back (new Property_printer<VIndex,Vcolor_map>(pmap));
return true;
}
}
return false;
}
template <typename Point>
bool fill_simplex_specific_header
(std::ostream& os, const Surface_mesh<Point>& sm,
std::vector<Abstract_property_printer<typename Surface_mesh<Point>::Face_index>*>& printers,
const std::string& prop)
{
typedef Surface_mesh<Point> SMesh;
typedef typename SMesh::Face_index FIndex;
typedef typename SMesh::template Property_map<FIndex, Color> Fcolor_map;
if (prop == "f:connectivity" ||
prop == "f:removed")
return true;
bool okay = false;
if (prop == "f:color")
{
Fcolor_map pmap;
boost::tie (pmap, okay) = sm.template property_map<FIndex,Color>(prop);
if (okay)
{
os << "property uchar red" << std::endl
<< "property uchar green" << std::endl
<< "property uchar blue" << std::endl
<< "property uchar alpha" << std::endl;
printers.push_back (new Property_printer<FIndex,Fcolor_map>(pmap));
return true;
}
}
return false;
}
template <typename Point>
bool fill_simplex_specific_header
(std::ostream& , const Surface_mesh<Point>& ,
std::vector<Abstract_property_printer<typename Surface_mesh<Point>::Edge_index>*>& ,
const std::string& prop)
{
if (prop == "e:removed")
return true;
return false;
}
template <typename Point>
bool fill_simplex_specific_header
(std::ostream& , const Surface_mesh<Point>& ,
std::vector<Abstract_property_printer<typename Surface_mesh<Point>::Halfedge_index>*>& ,
const std::string& prop)
{
if (prop == "h:connectivity")
return true;
return false;
}
template <typename Point>
std::string get_property_raw_name (const std::string& prop, typename Surface_mesh<Point>::Vertex_index)
{
std::string name = prop;
if (name.rfind("v:",0) == 0)
name = std::string (prop.begin() + 2, prop.end());
return name;
}
template <typename Point>
std::string get_property_raw_name (const std::string& prop, typename Surface_mesh<Point>::Face_index)
{
std::string name = prop;
if (name.rfind("f:",0) == 0)
name = std::string (prop.begin() + 2, prop.end());
return name;
}
template <typename Point>
std::string get_property_raw_name (const std::string& prop, typename Surface_mesh<Point>::Edge_index)
{
std::string name = prop;
if (name.rfind("e:",0) == 0)
name = std::string (prop.begin() + 2, prop.end());
return name;
}
template <typename Point>
std::string get_property_raw_name (const std::string& prop, typename Surface_mesh<Point>::Halfedge_index)
{
std::string name = prop;
if (name.rfind("h:",0) == 0)
name = std::string (prop.begin() + 2, prop.end());
return name;
}
template <typename Point, typename Simplex>
void fill_header (std::ostream& os, const Surface_mesh<Point>& sm,
std::vector<Abstract_property_printer<Simplex>*>& printers)
{
typedef Surface_mesh<Point> SMesh;
typedef typename SMesh::template Property_map<Simplex, boost::int8_t> Int8_map;
typedef typename SMesh::template Property_map<Simplex, boost::uint8_t> Uint8_map;
typedef typename SMesh::template Property_map<Simplex, boost::int16_t> Int16_map;
typedef typename SMesh::template Property_map<Simplex, boost::uint16_t> Uint16_map;
typedef typename SMesh::template Property_map<Simplex, boost::int32_t> Int32_map;
typedef typename SMesh::template Property_map<Simplex, boost::uint32_t> Uint32_map;
typedef typename SMesh::template Property_map<Simplex, boost::int64_t> Int64_map;
typedef typename SMesh::template Property_map<Simplex, boost::uint64_t> Uint64_map;
typedef typename SMesh::template Property_map<Simplex, float> Float_map;
typedef typename SMesh::template Property_map<Simplex, double> Double_map;
std::vector<std::string> prop = sm.template properties<Simplex>();
for (std::size_t i = 0; i < prop.size(); ++ i)
{
if (fill_simplex_specific_header(os, sm, printers, prop[i]))
continue;
// Cut the "v:" prefix
std::string name = get_property_raw_name<Point> (prop[i], Simplex());
bool okay = false;
{
Int8_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::int8_t>(prop[i]);
if (okay)
{
os << "property char " << name << std::endl;
printers.push_back (new internal::PLY::Char_property_printer<Simplex,Int8_map>(pmap));
continue;
}
}
{
Uint8_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::uint8_t>(prop[i]);
if (okay)
{
os << "property uchar " << name << std::endl;
printers.push_back (new internal::PLY::Char_property_printer<Simplex,Uint8_map>(pmap));
continue;
}
}
{
Int16_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::int16_t>(prop[i]);
if (okay)
{
os << "property short " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Int16_map>(pmap));
continue;
}
}
{
Uint16_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::uint16_t>(prop[i]);
if (okay)
{
os << "property ushort " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Uint16_map>(pmap));
continue;
}
}
{
Int32_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::int32_t>(prop[i]);
if (okay)
{
os << "property int " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Int32_map>(pmap));
continue;
}
}
{
Uint32_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::uint32_t>(prop[i]);
if (okay)
{
os << "property uint " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Uint32_map>(pmap));
continue;
}
}
{
Int64_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::int64_t>(prop[i]);
if (okay)
{
os << "property int " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Int64_map,boost::int32_t>(pmap));
continue;
}
}
{
Uint64_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,boost::uint64_t>(prop[i]);
if (okay)
{
os << "property uint " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Uint64_map,boost::uint32_t>(pmap));
continue;
}
}
{
Float_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,float>(prop[i]);
if (okay)
{
os << "property float " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Float_map>(pmap));
continue;
}
}
{
Double_map pmap;
boost::tie (pmap, okay) = sm.template property_map<Simplex,double>(prop[i]);
if (okay)
{
os << "property double " << name << std::endl;
printers.push_back (new internal::PLY::Simple_property_printer<Simplex,Double_map>(pmap));
continue;
}
}
}
}
} // namespace PLY
#endif
} // namespace internal
} // namespace CGAL
#endif // CGAL_SURFACE_MESH_IO_PLY

View File

@ -53,6 +53,7 @@
#include <CGAL/boost/graph/iterator.h>
#include <CGAL/boost/graph/Euler_operations.h>
#include <CGAL/IO/File_scanner_OFF.h>
#include <CGAL/Surface_mesh/IO/PLY.h>
#include <CGAL/Handle_hash_function.h>
#include <CGAL/boost/graph/named_params_helper.h>
#include <CGAL/boost/graph/named_function_params.h>
@ -2164,6 +2165,188 @@ private: //------------------------------------------------------- private data
return os;
}
#if !defined(CGAL_CFG_NO_CPP0X_RVALUE_REFERENCE) && !defined(CGAL_CFG_NO_CPP0X_VARIADIC_TEMPLATES)
/// \relates Surface_mesh
/// Inserts the surface mesh in an output stream in PLY format.
/// If found, "v:normal", "v:color" and "f:color" are inserted in the stream.
/// All other vertex and face properties with simple types are inserted in the stream.
/// Edges are only inserted in the stream if they have at least one
/// property with simple type: if they do, all edge properties with
/// simple types are inserted in the stream. The halfedges follow
/// the same behavior.
///
/// If provided, the `comments` string is included line by line in
/// the header of the PLY stream (each line will be precedeed by
/// "comment ").
///
template <typename P>
bool write_ply(std::ostream& os, const Surface_mesh<P>& sm, const std::string& comments = std::string())
{
typedef Surface_mesh<P> SMesh;
typedef typename SMesh::Vertex_index VIndex;
typedef typename SMesh::Face_index FIndex;
typedef typename SMesh::Edge_index EIndex;
typedef typename SMesh::Halfedge_index HIndex;
os << "ply" << std::endl
<< ((get_mode(os) == IO::BINARY) ? "format binary_little_endian 1.0" : "format ascii 1.0") << std::endl
<< "comment Generated by the CGAL library" << std::endl;
if (comments != std::string())
{
std::istringstream iss (comments);
std::string line;
while (getline(iss, line))
{
if (line != "Generated by the CGAL library") // Avoid repeating the line if multiple savings
os << "comment " << line << std::endl;
}
}
os << "element vertex " << sm.number_of_vertices() << std::endl;
std::vector<internal::PLY::Abstract_property_printer<VIndex>*> vprinters;
internal::PLY::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<internal::PLY::Abstract_property_printer<FIndex>*> fprinters;
internal::PLY::fill_header (os, sm, fprinters);
std::vector<internal::PLY::Abstract_property_printer<EIndex>*> eprinters;
if (sm.template properties<EIndex>().size() > 1)
{
os << "element edge " << sm.number_of_edges() << std::endl;
os << "property int v0" << std::endl;
os << "property int v1" << std::endl;
internal::PLY::fill_header (os, sm, eprinters);
}
std::vector<internal::PLY::Abstract_property_printer<HIndex>*> hprinters;
if (sm.template properties<HIndex>().size() > 1)
{
os << "element halfedge " << sm.number_of_halfedges() << std::endl;
os << "property int source" << std::endl;
os << "property int target" << std::endl;
internal::PLY::fill_header (os, sm, hprinters);
}
os << "end_header" << std::endl;
BOOST_FOREACH(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;
BOOST_FOREACH(FIndex fi, sm.faces())
{
// Get list of vertex indices
polygon.clear();
BOOST_FOREACH(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())
{
BOOST_FOREACH(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())
{
BOOST_FOREACH(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
@ -2222,7 +2405,7 @@ private: //------------------------------------------------------- private data
if(!is){
return false;
}
sm.reserve(sm.num_vertices()+n, sm.num_faces()+2*f, sm.num_edges()+e);
sm.reserve(sm.num_vertices()+n, sm.num_edges()+e, sm.num_faces()+f);
std::vector<Vertex_index> vertexmap(n);
P p;
Vector_3 v;
@ -2324,6 +2507,133 @@ private: //------------------------------------------------------- private data
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;
}
internal::PLY::PLY_reader reader;
internal::PLY::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)
{
internal::PLY::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)
{
internal::PLY::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()`.

View File

@ -0,0 +1,38 @@
ply
format ascii 1.0
element vertex 4
property double x
property double y
property double z
property double nx
property double ny
property double nz
property uchar red
property uchar green
property uchar blue
property int id
element face 4
property list uchar int vertex_indices
property uchar red
property uchar green
property uchar blue
property int label
element edge 6
property int v0
property int v1
property float confidence
end_header
0 0 0 -0.5 -0.5 -0.5 255 255 0 0
0 0 1 -0.5 -0.5 0 0 255 255 1
0 1 0 -0.5 0 -0.5 128 0 255 2
1 0 0 0 -0.5 -0.5 255 128 0 3
3 0 1 2 255 0 0 -1
3 0 3 1 0 255 0 1
3 1 3 2 0 0 255 -1
3 0 2 3 255 0 255 0
0 1 0.1
0 2 0.2
0 3 0.3
1 2 0.4
1 3 0.5
2 3 0.6

View File

@ -0,0 +1,46 @@
#include <CGAL/Surface_mesh/Surface_mesh.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <cstring>
#include <iostream>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> SMesh;
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
typedef boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
int main()
{
std::ifstream in ("colored_tetra.ply");
SMesh mesh;
CGAL::read_ply (in, mesh);
std::cerr << "Read mesh with " << mesh.number_of_vertices() << " vertices and "
<< mesh.number_of_faces() << " faces" << std::endl;
std::cerr << "Properties associated with vertices:" << std::endl;
std::vector<std::string> properties = mesh.properties<SMesh::Vertex_index>();
for (std::size_t i = 0; i < properties.size(); ++ i)
std::cerr << " * " << properties[i] << std::endl;
std::cerr << "Properties associated with faces:" << std::endl;
properties = mesh.properties<SMesh::Face_index>();
for (std::size_t i = 0; i < properties.size(); ++ i)
std::cerr << " * " << properties[i] << std::endl;
mesh.add_property_map<SMesh::Edge_index, short>("id", 42);
mesh.add_property_map<SMesh::Halfedge_index, float>("u", 13.f);
mesh.add_property_map<SMesh::Halfedge_index, float>("v", 37.f);
// Append second mesh
std::ifstream in2 ("tetra.ply");
CGAL::read_ply (in2, mesh);
std::ofstream out ("out.ply");
// CGAL::set_binary_mode(out);
CGAL::write_ply (out, mesh);
return 0;
}

View File

@ -0,0 +1,14 @@
ply
format ascii 1.0
element vertex 3
property double x
property double y
property double z
property int blabla
element face 1
property list uchar int vertex_indices
end_header
0 0 2 1000
0 1 2 200
1 0 2 30
3 0 1 2