mirror of https://github.com/CGAL/cgal
Merge pull request #400 from sgiraudot/Point_set_processing_3-IO_ply-GF
Read and write PLY point clouds
This commit is contained in:
commit
1dbac9df32
|
|
@ -174,6 +174,10 @@ and <code>src/</code> directories).
|
|||
automatically adapt the local density of points to the local
|
||||
variation of the input computed by principal component analysis.
|
||||
</li>
|
||||
<li> New IO functions for PLY format (Polygon File
|
||||
Format): <code>CGAL::read_ply_points()</code>,
|
||||
<code>CGAL::read_ply_points_and_normals()</code>, <code>CGAL::write_ply_points()</code>
|
||||
and <code>CGAL::write_ply_points_and_normals()</code>.</li>
|
||||
</ul>
|
||||
<h3>Surface Mesh Parameterization</h3>
|
||||
<ul>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
## Functions ##
|
||||
|
||||
- `CGAL::read_off_points()`
|
||||
- `CGAL::read_ply_points()`
|
||||
- `CGAL::read_xyz_points()`
|
||||
- `CGAL::compute_average_spacing()`
|
||||
- `CGAL::remove_outliers()`
|
||||
|
|
@ -42,6 +43,7 @@
|
|||
- `CGAL::vcm_estimate_normals()`
|
||||
- `CGAL::vcm_is_on_feature_edge()`
|
||||
- `CGAL::write_off_points()`
|
||||
- `CGAL::write_ply_points()`
|
||||
- `CGAL::write_xyz_points()`
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -80,13 +80,19 @@ a property map.
|
|||
We provide functions to read and write sets of points or sets of
|
||||
points with normals from the following ASCII file formats: XYZ (three
|
||||
point coordinates `x y z` per line or three point coordinates and
|
||||
three normal vector coordinates `x y z nx ny nz` per line), and OFF
|
||||
(%Object File Format) \cgalCite{cgal:p-gmgv16-96}.
|
||||
three normal vector coordinates `x y z nx ny nz` per line), OFF
|
||||
(%Object File Format) \cgalCite{cgal:p-gmgv16-96} and PLY (Polygon
|
||||
File Format).
|
||||
|
||||
- `read_xyz_points()`
|
||||
- `read_off_points()`
|
||||
- `read_off_points()`
|
||||
- `read_ply_points()`
|
||||
- `write_off_points()`
|
||||
- `write_xyz_points()`
|
||||
- `write_xyz_points()`
|
||||
- `write_ply_points()`
|
||||
|
||||
Note that `read_ply_points()` also accepts binary PLY format in
|
||||
addition of ASCII.
|
||||
|
||||
\subsection Point_set_processing_3Example Example
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,615 @@
|
|||
// 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
|
||||
// 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$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#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>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#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;
|
||||
|
||||
// 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, boost::int8_t& c) const
|
||||
{
|
||||
short s;
|
||||
stream >> s;
|
||||
c = static_cast<char>(s);
|
||||
}
|
||||
void read_ascii (std::istream& stream, boost::uint8_t& c) const
|
||||
{
|
||||
unsigned short s;
|
||||
stream >> s;
|
||||
c = static_cast<unsigned char>(s);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
};
|
||||
|
||||
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<boost::int8_t> (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<boost::uint8_t> (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<boost::int16_t> (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<boost::uint16_t> (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<boost::int32_t> (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<boost::uint32_t> (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 (ASCII or binary).
|
||||
/// Potential additional point properties and 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 = ASCII;
|
||||
|
||||
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" || type == "int8")
|
||||
readers.push_back (new internal::Ply_read_char (name, format));
|
||||
else if (type == "uchar" || type == "uint8")
|
||||
readers.push_back (new internal::Ply_read_uchar (name, format));
|
||||
else if (type == "short" || type == "int16")
|
||||
readers.push_back (new internal::Ply_read_short (name, format));
|
||||
else if (type == "ushort" || type == "uint16")
|
||||
readers.push_back (new internal::Ply_read_ushort (name, format));
|
||||
else if (type == "int" || type == "int32")
|
||||
readers.push_back (new internal::Ply_read_int (name, format));
|
||||
else if (type == "uint" || type == "uint32")
|
||||
readers.push_back (new internal::Ply_read_uint (name, format));
|
||||
else if (type == "float" || type == "float32")
|
||||
readers.push_back (new internal::Ply_read_float (name, format));
|
||||
else if (type == "double" || type == "float64")
|
||||
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 = 0., y = 0., z = 0., nx = 0., ny = 0., nz = 0.;
|
||||
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 (ASCII or binary).
|
||||
/// Potential additional point properties (including normals) and 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
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
// 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
|
||||
// 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$
|
||||
//
|
||||
// Author(s) : Simon Giraudot
|
||||
|
||||
#ifndef CGAL_WRITE_PLY_POINTS_H
|
||||
#define CGAL_WRITE_PLY_POINTS_H
|
||||
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/point_set_processing_assertions.h>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
||||
//===================================================================================
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
/// Saves the [first, beyond) range of points (positions + normals) to a .ply ASCII stream.
|
||||
///
|
||||
/// \pre normals must be unit vectors
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with value type `Point_3<Kernel>`.
|
||||
/// It can be omitted if the value type of `ForwardIterator` is convertible to `Point_3<Kernel>`.
|
||||
/// @tparam NormalPMap is a model of `ReadablePropertyMap` with a 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 ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap,
|
||||
typename Kernel >
|
||||
bool
|
||||
write_ply_points_and_normals(
|
||||
std::ostream& stream, ///< output stream.
|
||||
ForwardIterator first, ///< iterator over the first input point.
|
||||
ForwardIterator beyond, ///< past-the-end iterator over the input points.
|
||||
PointPMap point_pmap, ///< property map: value_type of ForwardIterator -> Point_3.
|
||||
NormalPMap normal_pmap, ///< property map: value_type of ForwardIterator -> Vector_3.
|
||||
const Kernel& /*kernel*/) ///< geometric traits.
|
||||
{
|
||||
// basic geometric types
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
|
||||
CGAL_point_set_processing_precondition(first != beyond);
|
||||
|
||||
if(!stream)
|
||||
{
|
||||
std::cerr << "Error: cannot open file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write header
|
||||
stream << "ply" << std::endl
|
||||
<< "format ascii 1.0" << std::endl
|
||||
<< "comment Generated by the CGAL library" << std::endl
|
||||
<< "element vertex " << std::distance (first, beyond) << std::endl
|
||||
<< "property double x" << std::endl
|
||||
<< "property double y" << std::endl
|
||||
<< "property double z" << std::endl
|
||||
<< "property double nx" << std::endl
|
||||
<< "property double ny" << std::endl
|
||||
<< "property double nz" << std::endl
|
||||
<< "end_header" << std::endl;
|
||||
|
||||
|
||||
// Write positions + normals
|
||||
for(ForwardIterator it = first; it != beyond; it++)
|
||||
{
|
||||
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
|
||||
Point p = get(point_pmap, it);
|
||||
Vector n = get(normal_pmap, it);
|
||||
#else
|
||||
Point p = get(point_pmap, *it);
|
||||
Vector n = get(normal_pmap, *it);
|
||||
#endif
|
||||
stream << p << " " << n << std::endl;
|
||||
}
|
||||
|
||||
return ! stream.fail();
|
||||
}
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// This variant deduces the kernel from the point property map.
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename NormalPMap >
|
||||
bool
|
||||
write_ply_points_and_normals(
|
||||
std::ostream& stream, ///< output stream.
|
||||
ForwardIterator first, ///< first input point.
|
||||
ForwardIterator beyond, ///< past-the-end input point.
|
||||
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 write_ply_points_and_normals(
|
||||
stream,
|
||||
first, beyond,
|
||||
point_pmap,
|
||||
normal_pmap,
|
||||
Kernel());
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// This variant creates a default point property map = Identity_property_map.
|
||||
template <typename ForwardIterator,
|
||||
typename NormalPMap
|
||||
>
|
||||
bool
|
||||
write_ply_points_and_normals(
|
||||
std::ostream& stream, ///< output stream.
|
||||
ForwardIterator first, ///< first input point.
|
||||
ForwardIterator beyond, ///< past-the-end input point.
|
||||
NormalPMap normal_pmap) ///< property map: value_type of OutputIterator -> Vector_3.
|
||||
{
|
||||
return write_ply_points_and_normals(
|
||||
stream,
|
||||
first, beyond,
|
||||
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
|
||||
make_dereference_property_map(first),
|
||||
#else
|
||||
make_identity_property_map(
|
||||
typename std::iterator_traits<ForwardIterator>::value_type()),
|
||||
#endif
|
||||
normal_pmap);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
|
||||
//===================================================================================
|
||||
/// \ingroup PkgPointSetProcessing
|
||||
/// Saves the [first, beyond) range of points (positions only) to a .ply ASCII stream.
|
||||
///
|
||||
/// @tparam ForwardIterator iterator over input points.
|
||||
/// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = `Point_3<Kernel>`.
|
||||
/// It can be omitted if the value type of `ForwardIterator` 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 ForwardIterator,
|
||||
typename PointPMap,
|
||||
typename Kernel >
|
||||
bool
|
||||
write_ply_points(
|
||||
std::ostream& stream, ///< output stream.
|
||||
ForwardIterator first, ///< iterator over the first input point.
|
||||
ForwardIterator beyond, ///< past-the-end iterator over the input points.
|
||||
PointPMap point_pmap, ///< property map: value_type of ForwardIterator -> Point_3.
|
||||
const Kernel& ) ///< geometric traits.
|
||||
{
|
||||
// basic geometric types
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
|
||||
CGAL_point_set_processing_precondition(first != beyond);
|
||||
|
||||
if(!stream)
|
||||
{
|
||||
std::cerr << "Error: cannot open file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write header
|
||||
stream << "ply" << std::endl
|
||||
<< "format ascii 1.0" << std::endl
|
||||
<< "comment Generated by the CGAL library" << std::endl
|
||||
<< "element vertex " << std::distance (first, beyond) << std::endl
|
||||
<< "property double x" << std::endl
|
||||
<< "property double y" << std::endl
|
||||
<< "property double z" << std::endl
|
||||
<< "end_header" << std::endl;
|
||||
|
||||
// Write positions
|
||||
for(ForwardIterator it = first; it != beyond; it++)
|
||||
{
|
||||
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
|
||||
Point p = get(point_pmap, it);
|
||||
#else
|
||||
Point p = get(point_pmap, *it);
|
||||
#endif
|
||||
stream << p << std::endl;
|
||||
}
|
||||
|
||||
return ! stream.fail();
|
||||
}
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// This variant deduces the kernel from the point property map.
|
||||
template < typename ForwardIterator,
|
||||
typename PointPMap >
|
||||
bool
|
||||
write_ply_points(
|
||||
std::ostream& stream, ///< output stream.
|
||||
ForwardIterator first, ///< first input point.
|
||||
ForwardIterator beyond, ///< past-the-end input point.
|
||||
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 write_ply_points(
|
||||
stream,
|
||||
first, beyond,
|
||||
point_pmap,
|
||||
Kernel());
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
/// @cond SKIP_IN_MANUAL
|
||||
// This variant creates a default point property map = Identity_property_map.
|
||||
template < typename ForwardIterator >
|
||||
bool
|
||||
write_ply_points(
|
||||
std::ostream& stream, ///< output stream.
|
||||
ForwardIterator first, ///< first input point.
|
||||
ForwardIterator beyond) ///< past-the-end input point.
|
||||
{
|
||||
return write_ply_points(
|
||||
stream,
|
||||
first, beyond,
|
||||
#ifdef CGAL_USE_PROPERTY_MAPS_API_V1
|
||||
make_dereference_property_map(first)
|
||||
#else
|
||||
make_identity_property_map(
|
||||
typename std::iterator_traits<ForwardIterator>::value_type())
|
||||
#endif
|
||||
);
|
||||
}
|
||||
/// @endcond
|
||||
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif // CGAL_WRITE_PLY_POINTS_H
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
OFF
|
||||
NOFF
|
||||
3 0 0
|
||||
1 1 1 2 2 2
|
||||
3 3 3 4 4 4
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -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
|
||||
Binary file not shown.
|
|
@ -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,23 @@ 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));
|
||||
assert(pv_pairs[0] == std::make_pair(Point_3(1,1,1), Vector_3(2,2,2)));
|
||||
assert(pv_pairs[1] == std::make_pair(Point_3(3,3,3), Vector_3(4,4,4)));
|
||||
assert(pv_pairs[2] == std::make_pair(Point_3(5,5,5), Vector_3(6,6,6)));
|
||||
|
||||
pv_pairs.clear ();
|
||||
assert(read_ply("data/read_test/simple_ascii.ply", pv_pairs));
|
||||
assert(pv_pairs[0] == std::make_pair(Point_3(1,1,1), Vector_3(2,2,2)));
|
||||
assert(pv_pairs[1] == std::make_pair(Point_3(3,3,3), Vector_3(4,4,4)));
|
||||
assert(pv_pairs[2] == std::make_pair(Point_3(5,5,5), Vector_3(6,6,6)));
|
||||
|
||||
pv_pairs.clear ();
|
||||
assert(read_ply("data/read_test/simple_with_flag.ply", pv_pairs));
|
||||
assert(pv_pairs[0] == std::make_pair(Point_3(1,1,1), Vector_3(2,2,2)));
|
||||
assert(pv_pairs[1] == std::make_pair(Point_3(3,3,3), Vector_3(4,4,4)));
|
||||
assert(pv_pairs[2] == std::make_pair(Point_3(5,5,5), Vector_3(6,6,6)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,6 +332,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)
|
||||
|
||||
|
|
|
|||
|
|
@ -56,14 +56,28 @@ Polyhedron_demo_off_to_xyz_plugin::load(QFileInfo fileinfo) {
|
|||
return item;
|
||||
}
|
||||
|
||||
bool Polyhedron_demo_off_to_xyz_plugin::canSave(const Scene_item*)
|
||||
bool Polyhedron_demo_off_to_xyz_plugin::canSave(const Scene_item* item)
|
||||
{
|
||||
return false;
|
||||
// This plugin supports point sets
|
||||
return qobject_cast<const Scene_points_with_normal_item*>(item);
|
||||
}
|
||||
|
||||
bool Polyhedron_demo_off_to_xyz_plugin::save(const Scene_item*, QFileInfo)
|
||||
bool Polyhedron_demo_off_to_xyz_plugin::save(const Scene_item* item, QFileInfo fileinfo)
|
||||
{
|
||||
return false;
|
||||
// Check extension (quietly)
|
||||
std::string extension = fileinfo.suffix().toUtf8().data();
|
||||
if (extension != "off" && extension != "OFF")
|
||||
return false;
|
||||
|
||||
// This plugin supports point sets
|
||||
const Scene_points_with_normal_item* point_set_item =
|
||||
qobject_cast<const Scene_points_with_normal_item*>(item);
|
||||
if(!point_set_item)
|
||||
return false;
|
||||
|
||||
// Save point set as .xyz
|
||||
std::ofstream out(fileinfo.filePath().toUtf8().data());
|
||||
return point_set_item->write_off_point_set(out);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
#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* item)
|
||||
{
|
||||
// This plugin supports point sets
|
||||
return qobject_cast<const Scene_points_with_normal_item*>(item);
|
||||
}
|
||||
|
||||
bool Polyhedron_demo_ply_to_xyz_plugin::save(const Scene_item* item, QFileInfo fileinfo)
|
||||
{
|
||||
// Check extension (quietly)
|
||||
std::string extension = fileinfo.suffix().toUtf8().data();
|
||||
if (extension != "ply" && extension != "PLY")
|
||||
return false;
|
||||
|
||||
// This plugin supports point sets
|
||||
const Scene_points_with_normal_item* point_set_item =
|
||||
qobject_cast<const Scene_points_with_normal_item*>(item);
|
||||
if(!point_set_item)
|
||||
return false;
|
||||
|
||||
// Save point set as .xyz
|
||||
std::ofstream out(fileinfo.filePath().toUtf8().data());
|
||||
return point_set_item->write_ply_point_set(out);
|
||||
}
|
||||
|
||||
|
||||
#include "Polyhedron_demo_ply_to_xyz_plugin.moc"
|
||||
|
|
@ -2,6 +2,8 @@
|
|||
#include "Polyhedron_type.h"
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
|
||||
#include <CGAL/IO/read_ply_points.h>
|
||||
#include <CGAL/IO/write_ply_points.h>
|
||||
#include <CGAL/IO/read_off_points.h>
|
||||
#include <CGAL/IO/write_off_points.h>
|
||||
#include <CGAL/IO/read_xyz_points.h>
|
||||
|
|
@ -271,6 +273,45 @@ 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();
|
||||
if (ok)
|
||||
{
|
||||
for (Point_set::iterator it=m_points->begin(),
|
||||
end=m_points->end();it!=end; ++it)
|
||||
{
|
||||
if (it->normal() != CGAL::NULL_VECTOR)
|
||||
{
|
||||
m_has_normals=true;
|
||||
setRenderingMode(PointsPlusNormals);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
invalidate_buffers();
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Write point set to .PLY file
|
||||
bool Scene_points_with_normal_item::write_ply_point_set(std::ostream& stream) const
|
||||
{
|
||||
Q_ASSERT(m_points != NULL);
|
||||
|
||||
return stream &&
|
||||
CGAL::write_ply_points_and_normals(stream,
|
||||
m_points->begin(), m_points->end(),
|
||||
CGAL::make_normal_of_point_with_normal_pmap(Point_set::value_type()));
|
||||
}
|
||||
|
||||
// Loads point set from .OFF file
|
||||
bool Scene_points_with_normal_item::read_off_point_set(std::istream& stream)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ public:
|
|||
QMenu* contextMenu();
|
||||
|
||||
// IO
|
||||
bool read_ply_point_set(std::istream& in);
|
||||
bool write_ply_point_set(std::ostream& out) const;
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
Loading…
Reference in New Issue