Merge branch 'Point_set_processing_3-IO_ply-GF-old' into Point_set_processing_3-IO_ply-GF

This commit is contained in:
Simon Giraudot 2015-10-07 13:52:06 +02:00
commit c2e38b72a6
11 changed files with 687 additions and 1 deletions

View File

@ -0,0 +1,573 @@
#ifndef CGAL_READ_PLY_POINTS_H
#define CGAL_READ_PLY_POINTS_H
#include <CGAL/property_map.h>
#include <CGAL/value_type_traits.h>
#include <CGAL/point_set_processing_assertions.h>
#include <boost/version.hpp>
#if BOOST_VERSION >= 104000
#include <boost/property_map/property_map.hpp>
#else
#include <boost/property_map.hpp>
#endif
#include <iostream>
#include <sstream>
#include <string>
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
namespace internal {
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 double operator() (std::istream& stream) const = 0;
template <typename Type>
Type read (std::istream& stream) const
{
if (m_format == 0) // Ascii
{
Type t;
stream >> t;
return t;
}
else // Binary (2 = little endian)
{
std::size_t size = sizeof (Type);
unsigned int buffer[size];
stream.read(reinterpret_cast<char*>(buffer), size);
if (m_format == 2) // Big endian
{
for (std::size_t i = 0; i < size / 2; ++ i)
{
unsigned char tmp = buffer[i];
buffer[i] = buffer[size - i];
buffer[size - i] = tmp;
}
}
return reinterpret_cast<Type&> (buffer);
}
return Type();
}
};
class Ply_read_char : public Ply_read_number
{
public:
Ply_read_char (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<char> (stream)); }
};
class Ply_read_uchar : public Ply_read_number
{
public:
Ply_read_uchar (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<unsigned char> (stream)); }
};
class Ply_read_short : public Ply_read_number
{
public:
Ply_read_short (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<short> (stream)); }
};
class Ply_read_ushort : public Ply_read_number
{
public:
Ply_read_ushort (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<unsigned short> (stream)); }
};
class Ply_read_int : public Ply_read_number
{
public:
Ply_read_int (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<int> (stream)); }
};
class Ply_read_uint : public Ply_read_number
{
public:
Ply_read_uint (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<unsigned int> (stream)); }
};
class Ply_read_float : public Ply_read_number
{
public:
Ply_read_float (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return static_cast<double> (this->read<float> (stream)); }
};
class Ply_read_double : public Ply_read_number
{
public:
Ply_read_double (std::string name, std::size_t format) : Ply_read_number (name, format) { }
double operator() (std::istream& stream) const
{ return this->read<float> (stream); }
};
} //namespace CGAL
//===================================================================================
/// \ingroup PkgPointSetProcessing
/// Reads points (positions + normals, if available) from a .ply stream.
/// Faces are ignored.
///
/// @tparam OutputIteratorValueType type of objects that can be put in `OutputIterator`.
/// It is default to `value_type_traits<OutputIterator>::%type` and can be omitted when the default is fine.
/// @tparam OutputIterator iterator over output points.
/// @tparam PointPMap is a model of `WritablePropertyMap` with value type `Point_3<Kernel>`.
/// It can be omitted if the value type of `OutputIterator` is convertible to `Point_3<Kernel>`.
/// @tparam NormalPMap is a model of `WritablePropertyMap` with value type `Vector_3<Kernel>`.
/// @tparam Kernel Geometric traits class.
/// It can be omitted and deduced automatically from the value type of `PointPMap`.
///
/// @return true on success.
// This variant requires all parameters.
//-----------------------------------------------------------------------------------
template < typename OutputIteratorValueType,
typename OutputIterator,
typename PointPMap,
typename NormalPMap,
typename Kernel >
bool read_ply_points_and_normals(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap, ///< property map: value_type of OutputIterator -> Point_3.
NormalPMap normal_pmap, ///< property map: value_type of OutputIterator -> Vector_3.
const Kernel& /*kernel*/) ///< geometric traits.
{
// value_type_traits is a workaround as back_insert_iterator's value_type is void
// typedef typename value_type_traits<OutputIterator>::type Enriched_point;
typedef OutputIteratorValueType Enriched_point;
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Vector_3 Vector;
typedef typename Kernel::FT FT;
if(!stream)
{
std::cerr << "Error: cannot open file" << std::endl;
return false;
}
// scan points
std::size_t pointsCount = 0, // number of items in file
pointsRead = 0, // current number of points read
lineNumber = 0; // current line number
enum Format { ASCII = 0, BINARY_LITTLE_ENDIAN = 1, BINARY_BIG_ENDIAN = 2};
Format format;
std::string line;
std::istringstream iss;
// Check the order of the properties of the point set
bool reading_properties = false;
std::vector<internal::Ply_read_number*> readers;
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 << "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 << "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")
{
if (!reading_properties)
continue;
std::string type, name;
if (!(iss >> type >> name))
{
std::cerr << "Error line " << lineNumber << " of file" << std::endl;
return false;
}
if (type == "char")
readers.push_back (new internal::Ply_read_char (name, format));
else if (type == "uchar")
readers.push_back (new internal::Ply_read_uchar (name, format));
else if (type == "short")
readers.push_back (new internal::Ply_read_short (name, format));
else if (type == "ushort")
readers.push_back (new internal::Ply_read_ushort (name, format));
else if (type == "int")
readers.push_back (new internal::Ply_read_int (name, format));
else if (type == "uint")
readers.push_back (new internal::Ply_read_uint (name, format));
else if (type == "float")
readers.push_back (new internal::Ply_read_float (name, format));
else if (type == "double")
readers.push_back (new internal::Ply_read_double (name, format));
continue;
}
else
reading_properties = false;
// ignore comments and properties (if not in element
// vertex - cf below - properties are useless in our case)
if (keyword == "comment" || keyword == "property")
continue;
// When end_header is reached, stop loop and begin reading points
if (keyword == "end_header")
break;
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;
}
if (type == "vertex")
{
pointsCount = number;
reading_properties = true;
}
else
continue;
}
}
}
while (!(stream.eof()) && pointsRead < pointsCount)
{
FT x, y, z, nx, ny, nz;
for (std::size_t i = 0; i < readers.size (); ++ i)
{
FT value = (*readers[i])(stream);
if (readers[i]->name () == "x") x = value;
else if (readers[i]->name () == "y") y = value;
else if (readers[i]->name () == "z") z = value;
else if (readers[i]->name () == "nx") nx = value;
else if (readers[i]->name () == "ny") ny = value;
else if (readers[i]->name () == "nz") nz = value;
}
Point point(x,y,z);
Vector normal(nx,ny,nz);
Enriched_point pwn;
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
put(point_pmap, &pwn, point); // point_pmap[&pwn] = point
put(normal_pmap, &pwn, normal); // normal_pmap[&pwn] = normal
#else
put(point_pmap, pwn, point); // point_pmap[&pwn] = point
put(normal_pmap, pwn, normal); // normal_pmap[&pwn] = normal
#endif
*output++ = pwn;
pointsRead++;
}
// Skip remaining lines
for (std::size_t i = 0; i < readers.size (); ++ i)
delete readers[i];
return true;
}
/// @cond SKIP_IN_MANUAL
template < typename OutputIterator,
typename PointPMap,
typename NormalPMap,
typename Kernel >
bool read_ply_points_and_normals(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap, ///< property map: value_type of OutputIterator -> Point_3.
NormalPMap normal_pmap, ///< property map: value_type of OutputIterator -> Vector_3.
const Kernel& kernel) ///< geometric traits.
{
// just deduce value_type of OutputIterator
return read_ply_points_and_normals
<typename value_type_traits<OutputIterator>::type>(stream,
output,
point_pmap,
normal_pmap,
kernel);
}
//-----------------------------------------------------------------------------------
/// @endcond
/// @cond SKIP_IN_MANUAL
// This variant deduces the kernel from the point property map.
//-----------------------------------------------------------------------------------
template < typename OutputIteratorValueType,
typename OutputIterator,
typename PointPMap,
typename NormalPMap >
bool read_ply_points_and_normals(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap, ///< property map: value_type of OutputIterator -> Point_3.
NormalPMap normal_pmap) ///< property map: value_type of OutputIterator -> Vector_3.
{
typedef typename boost::property_traits<PointPMap>::value_type Point;
typedef typename Kernel_traits<Point>::Kernel Kernel;
return read_ply_points_and_normals
<OutputIteratorValueType>(stream,
output,
point_pmap,
normal_pmap,
Kernel());
}
template < typename OutputIterator,
typename PointPMap,
typename NormalPMap >
bool read_ply_points_and_normals(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap, ///< property map: value_type of OutputIterator -> Point_3.
NormalPMap normal_pmap) ///< property map: value_type of OutputIterator -> Vector_3.
{
// just deduce value_type of OutputIterator
return read_ply_points_and_normals
<typename value_type_traits<OutputIterator>::type>(stream,
output,
point_pmap,
normal_pmap);
}
//-----------------------------------------------------------------------------------
/// @endcond
/// @cond SKIP_IN_MANUAL
// This variant creates a default point property map = Identity_property_map.
//-----------------------------------------------------------------------------------
template < typename OutputIteratorValueType,
typename OutputIterator,
typename NormalPMap >
bool read_ply_points_and_normals(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
NormalPMap normal_pmap) ///< property map: value_type of OutputIterator -> Vector_3.
{
return read_ply_points_and_normals
<OutputIteratorValueType>(stream,
output,
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
make_dereference_property_map(output),
#else
make_identity_property_map(OutputIteratorValueType()),
#endif
normal_pmap);
}
template < typename OutputIterator,
typename NormalPMap >
bool read_ply_points_and_normals(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
NormalPMap normal_pmap) ///< property map: value_type of OutputIterator -> Vector_3.
{
// just deduce value_type of OutputIterator
return read_ply_points_and_normals
<typename value_type_traits<OutputIterator>::type>(stream,
output,
normal_pmap);
}
//-----------------------------------------------------------------------------------
/// @endcond
//===================================================================================
/// \ingroup PkgPointSetProcessing
/// Reads points (position only) from a .ply stream.
/// If the position is followed by the nx ny nz normal, then the normal will be ignored.
/// Faces are ignored.
///
/// @tparam OutputIteratorValueType type of objects that can be put in `OutputIterator`.
/// It is default to `value_type_traits<OutputIterator>::%type` and can be omitted when the default is fine.
/// @tparam OutputIterator iterator over output points.
/// @tparam PointPMap is a model of `WritablePropertyMap` with value_type `Point_3<Kernel>`.
/// It can be omitted if the value type of `OutputIterator` is convertible to `Point_3<Kernel>`.
/// @tparam Kernel Geometric traits class.
/// It can be omitted and deduced automatically from the value type of `PointPMap`.
///
/// @return `true` on success.
// This variant requires all parameters.
//-----------------------------------------------------------------------------------
template < typename OutputIteratorValueType,
typename OutputIterator,
typename PointPMap,
typename Kernel >
bool read_ply_points(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap, ///< property map: value_type of OutputIterator -> Point_3.
const Kernel& kernel) ///< geometric traits.
{
// Calls read_ply_points_and_normals() with a normal property map = boost::dummy_property_map
return read_ply_points_and_normals
<OutputIteratorValueType>(stream,
output,
point_pmap,
boost::dummy_property_map(),
kernel);
}
/// @cond SKIP_IN_MANUAL
template < typename OutputIterator,
typename PointPMap,
typename Kernel >
bool read_ply_points(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap, ///< property map: value_type of OutputIterator -> Point_3.
const Kernel& kernel) ///< geometric traits.
{
// just deduce value_type of OutputIterator
return read_ply_points
<typename value_type_traits<OutputIterator>::type>(stream,
output,
point_pmap,
kernel);
}
//-----------------------------------------------------------------------------------
/// @endcond
/// @cond SKIP_IN_MANUAL
// This variant deduces the kernel from the point property map.
//-----------------------------------------------------------------------------------
template < typename OutputIteratorValueType,
typename OutputIterator,
typename PointPMap >
bool read_ply_points(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap) ///< property map: value_type of OutputIterator -> Point_3.
{
typedef typename boost::property_traits<PointPMap>::value_type Point;
typedef typename Kernel_traits<Point>::Kernel Kernel;
return read_ply_points
<OutputIteratorValueType>(stream,
output,
point_pmap,
Kernel());
}
template < typename OutputIterator,
typename PointPMap >
bool read_ply_points(std::istream& stream, ///< input stream.
OutputIterator output, ///< output iterator over points.
PointPMap point_pmap) ///< property map: value_type of OutputIterator -> Point_3.
{
// just deduce value_type of OutputIterator
return read_ply_points
<typename value_type_traits<OutputIterator>::type>(stream,
output,
point_pmap);
}
//-----------------------------------------------------------------------------------
/// @endcond
/// @cond SKIP_IN_MANUAL
// This variant creates a default point property map = Identity_property_map.
//-----------------------------------------------------------------------------------
template < typename OutputIteratorValueType,
typename OutputIterator >
bool read_ply_points(std::istream& stream, ///< input stream.
OutputIterator output) ///< output iterator over points.
{
return read_ply_points
<OutputIteratorValueType>(stream,
output,
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
make_dereference_property_map(output)
#else
make_identity_property_map(OutputIteratorValueType())
#endif
);
}
template < typename OutputIterator>
bool read_ply_points(std::istream& stream, ///< input stream.
OutputIterator output) ///< output iterator over points.
{
// just deduce value_type of OutputIterator
return read_ply_points
<typename value_type_traits<OutputIterator>::type>(stream,
output);
}
//-----------------------------------------------------------------------------------
/// @endcond
} //namespace CGAL
#endif // CGAL_READ_PLY_POINTS_H

View File

@ -1,4 +1,4 @@
OFF
NOFF
3 0 0
1 1 1 2 2 2
3 3 3 4 4 4

View File

@ -0,0 +1,16 @@
ply
format ascii 1.0
comment VCGLIB generated
element vertex 3
property float x
property float y
property float z
property float nx
property float ny
property float nz
element face 0
property list uchar int vertex_indices
end_header
1 1 1 2 2 2
3 3 3 4 4 4
5 5 5 6 6 6

View File

@ -2,6 +2,7 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/property_map.h>
#include <CGAL/IO/read_off_points.h>
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/IO/read_xyz_points.h>
#include <vector>
@ -47,6 +48,17 @@ bool read_off(std::string s,
CGAL::Second_of_pair_property_map<PointVectorPair>());
}
bool read_ply (std::string s,
std::vector<PointVectorPair>& pv_pairs)
{
std::ifstream fs(s.c_str());
return CGAL::read_ply_points_and_normals (fs,
back_inserter(pv_pairs),
CGAL::First_of_pair_property_map<PointVectorPair>(),
CGAL::Second_of_pair_property_map<PointVectorPair>());
}
int main()
{
@ -78,6 +90,12 @@ int main()
assert(pv_pairs[2] == std::make_pair(Point_3(4,5,6), Vector_3(0,0,0)));
assert(pv_pairs[3] == std::make_pair(Point_3(7,8,9), Vector_3(0,0,0)));
pv_pairs.clear ();
assert(read_ply("data/read_test/simple.ply", pv_pairs));
pv_pairs.clear ();
assert(read_ply("data/read_test/simple_ascii.ply", pv_pairs));
pv_pairs.clear ();
assert(read_ply("data/read_test/simple_with_flag.ply", pv_pairs));
return 0;
}

View File

@ -319,6 +319,9 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND)
polyhedron_demo_plugin(off_to_xyz_plugin Polyhedron_demo_off_to_xyz_plugin)
target_link_libraries(off_to_xyz_plugin scene_points_with_normal_item)
polyhedron_demo_plugin(ply_to_xyz_plugin Polyhedron_demo_ply_to_xyz_plugin)
target_link_libraries(ply_to_xyz_plugin scene_points_with_normal_item)
polyhedron_demo_plugin(convex_hull_plugin Polyhedron_demo_convex_hull_plugin)
target_link_libraries(convex_hull_plugin scene_polyhedron_item scene_points_with_normal_item scene_polylines_item scene_polyhedron_selection_item)

View File

@ -0,0 +1,58 @@
#include "Scene_points_with_normal_item.h"
#include "Polyhedron_demo_io_plugin_interface.h"
#include <fstream>
class Polyhedron_demo_ply_to_xyz_plugin :
public QObject,
public Polyhedron_demo_io_plugin_interface
{
Q_OBJECT
Q_INTERFACES(Polyhedron_demo_io_plugin_interface)
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.IOPluginInterface/1.0")
public:
QString name() const { return "ply_to_xyz_plugin"; }
QString nameFilters() const { return "PLY files as Point set (*.ply)"; }
bool canLoad() const;
Scene_item* load(QFileInfo fileinfo);
bool canSave(const Scene_item*);
bool save(const Scene_item*, QFileInfo fileinfo);
};
bool Polyhedron_demo_ply_to_xyz_plugin::canLoad() const {
return true;
}
Scene_item*
Polyhedron_demo_ply_to_xyz_plugin::load(QFileInfo fileinfo) {
std::ifstream in(fileinfo.filePath().toUtf8());
if(!in)
std::cerr << "Error!\n";
Scene_points_with_normal_item* item;
item = new Scene_points_with_normal_item();
if(!item->read_ply_point_set(in))
{
delete item;
return 0;
}
item->setName(fileinfo.baseName());
return item;
}
bool Polyhedron_demo_ply_to_xyz_plugin::canSave(const Scene_item*)
{
return false;
}
bool Polyhedron_demo_ply_to_xyz_plugin::save(const Scene_item*, QFileInfo)
{
return false;
}
#include "Polyhedron_demo_ply_to_xyz_plugin.moc"

View File

@ -2,6 +2,7 @@
#include "Polyhedron_type.h"
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
#include <CGAL/IO/read_ply_points.h>
#include <CGAL/IO/read_off_points.h>
#include <CGAL/IO/write_off_points.h>
#include <CGAL/IO/read_xyz_points.h>
@ -317,6 +318,21 @@ void Scene_points_with_normal_item::selectDuplicates()
Q_EMIT itemChanged();
}
// Loads point set from .PLY file
bool Scene_points_with_normal_item::read_ply_point_set(std::istream& stream)
{
Q_ASSERT(m_points != NULL);
m_points->clear();
bool ok = stream &&
CGAL::read_ply_points_and_normals(stream,
std::back_inserter(*m_points),
CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type())) &&
!isEmpty();
invalidate_buffers();
return ok;
}
// Loads point set from .OFF file
bool Scene_points_with_normal_item::read_off_point_set(std::istream& stream)
{

View File

@ -36,6 +36,7 @@ public:
QMenu* contextMenu();
// IO
bool read_ply_point_set(std::istream& in);
bool read_off_point_set(std::istream& in);
bool write_off_point_set(std::ostream& out) const;
bool read_xyz_point_set(std::istream& in);

View File

@ -126,6 +126,7 @@ else
orient_soup_plugin \
parameterization_plugin \
pca_plugin \
ply_to_xyz_plugin \
point_dialog \
point_inside_polyhedron_plugin \
point_set_average_spacing_plugin \