Skip to content

Commit dfc5fb5

Browse files
authored
IO: write_PLY() for Epeck (#7874)
## Summary of Changes As reported in #7868 the function `CGAL::IO::write_PLY()` used in binary mode does not correctly write the coordinates if the points are from a kernel with exact constructions. ~~This PR applies `to_double()" to the coordinates.~~ ~~After a discussion with @MaelRL we decided that the user is in charge to pass a `vertex_point_map` as named parameter that does the conversion. This is straightforward as we offer the [`Cartesian_converter_property_map`](https://doc.cgal.org/latest/Property_map/structCGAL_1_1Cartesian__converter__property__map.html).~~ Moving back to the previous proposal: hardcode some to_double and to_float casts such that we meet the requirements of the file format, whatever the input. As the problem is the same for the vertex normals we add a named parameter `vertex_normal_map`. ### Todo - [x] Fix the generic function `write_polygon_mesh()`. Currently it is fixed for `Surface_mesh` ## Release Management * Affected package(s): Stream_support * Issue(s) solved (if any): fix #7868 and fix #7327 * License and copyright ownership: unchanged * upcoming integration, update #9072 and test it
2 parents af94906 + 622b652 commit dfc5fb5

File tree

13 files changed

+582
-51
lines changed

13 files changed

+582
-51
lines changed

BGL/include/CGAL/boost/graph/IO/PLY.h

Lines changed: 131 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <CGAL/boost/graph/IO/Generic_facegraph_builder.h>
1919
#include <CGAL/Named_function_parameters.h>
2020
#include <CGAL/boost/graph/named_params_helper.h>
21+
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
2122

2223
#include <fstream>
2324
#include <string>
@@ -44,27 +45,30 @@ class PLY_builder
4445
typedef typename Base::Face_container Face_container;
4546

4647
public:
47-
PLY_builder(std::istream& is) : Base(is) { }
48+
PLY_builder(std::istream& is, std::string& comments) : Base(is), comments(comments) { }
4849

4950
template <typename NamedParameters>
5051
bool read(std::istream& is,
5152
Point_container& points,
5253
Face_container& faces,
5354
const NamedParameters& np)
5455
{
55-
return read_PLY(is, points, faces, np);
56+
return read_PLY(is, points, faces, comments, np);
5657
}
58+
59+
std::string& comments;
5760
};
5861

5962
template <typename Graph, typename CGAL_NP_TEMPLATE_PARAMETERS>
6063
bool read_PLY_BGL(std::istream& is,
6164
Graph& g,
65+
std::string& comments,
6266
const CGAL_NP_CLASS& np = parameters::default_values())
6367
{
6468
typedef typename CGAL::GetVertexPointMap<Graph, CGAL_NP_CLASS>::type VPM;
6569
typedef typename boost::property_traits<VPM>::value_type Point;
6670

67-
internal::PLY_builder<Graph, Point> builder(is);
71+
internal::PLY_builder<Graph, Point> builder(is, comments);
6872
return builder(g, np);
6973
}
7074

@@ -84,6 +88,7 @@ bool read_PLY_BGL(std::istream& is,
8488
8589
\param is the input stream
8690
\param g the graph to be built from the input data
91+
\param comments a string included line by line in the header of the PLY stream (each line will be precedeed by "comment ")
8792
\param np optional \ref bgl_namedparameters "Named Parameters" described below
8893
8994
\cgalNamedParamsBegin
@@ -128,6 +133,20 @@ bool read_PLY_BGL(std::istream& is,
128133
129134
\sa Overloads of this function for specific models of the concept `FaceGraph`.
130135
*/
136+
template <typename Graph,
137+
typename CGAL_NP_TEMPLATE_PARAMETERS>
138+
bool read_PLY(std::istream& is,
139+
Graph& g,
140+
std::string& comments,
141+
const CGAL_NP_CLASS& np = parameters::default_values()
142+
#ifndef DOXYGEN_RUNNING
143+
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
144+
#endif
145+
)
146+
{
147+
return internal::read_PLY_BGL(is, g, comments, np);
148+
}
149+
131150
template <typename Graph,
132151
typename CGAL_NP_TEMPLATE_PARAMETERS>
133152
bool read_PLY(std::istream& is,
@@ -138,9 +157,11 @@ bool read_PLY(std::istream& is,
138157
#endif
139158
)
140159
{
141-
return internal::read_PLY_BGL(is, g, np);
160+
std::string unused_comments;
161+
return internal::read_PLY_BGL(is, g, unused_comments, np);
142162
}
143163

164+
144165
/*!
145166
\ingroup PkgBGLIoFuncsPLY
146167
@@ -153,6 +174,7 @@ bool read_PLY(std::istream& is,
153174
154175
\param fname the name of the input file
155176
\param g the graph to be built from the input data
177+
\param comments a string included line by line in the header of the PLY stream (each line will be precedeed by "comment" )
156178
\param np optional \ref bgl_namedparameters "Named Parameters" described below
157179
158180
\cgalNamedParamsBegin
@@ -207,6 +229,7 @@ template <typename Graph,
207229
typename CGAL_NP_TEMPLATE_PARAMETERS>
208230
bool read_PLY(const std::string& fname,
209231
Graph& g,
232+
std::string& comments,
210233
const CGAL_NP_CLASS& np = parameters::default_values()
211234
#ifndef DOXYGEN_RUNNING
212235
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
@@ -218,16 +241,29 @@ bool read_PLY(const std::string& fname,
218241
{
219242
std::ifstream is(fname, std::ios::binary);
220243
CGAL::IO::set_mode(is, CGAL::IO::BINARY);
221-
return internal::read_PLY_BGL(is, g, np);
244+
return read_PLY(is, g, comments, np);
222245
}
223246
else
224247
{
225248
std::ifstream is(fname);
226249
CGAL::IO::set_mode(is, CGAL::IO::ASCII);
227-
return internal::read_PLY_BGL(is, g, np);
250+
return read_PLY(is, g, comments, np);
228251
}
229252
}
230253

254+
template <typename Graph,
255+
typename CGAL_NP_TEMPLATE_PARAMETERS>
256+
bool read_PLY(const std::string& fname,
257+
Graph& g,
258+
const CGAL_NP_CLASS& np = parameters::default_values()
259+
#ifndef DOXYGEN_RUNNING
260+
, std::enable_if_t<!internal::is_Point_set_or_Range_or_Iterator<Graph>::value>* = nullptr
261+
#endif
262+
)
263+
{
264+
std::string unused_comment;
265+
return read_PLY(fname, g, unused_comment, np);
266+
}
231267
////////////////////////////////////////////////////////////////////////////////////////////////////
232268
////////////////////////////////////////////////////////////////////////////////////////////////////
233269
// Write
@@ -259,6 +295,15 @@ bool read_PLY(const std::string& fname,
259295
must be available in `Graph`.}
260296
\cgalParamNEnd
261297
298+
\cgalParamNBegin{vertex_normal_map}
299+
\cgalParamDescription{a property map associating normals to the vertices of `g`}
300+
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
301+
as key type and `%Vector_3` as value type}
302+
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
303+
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
304+
must be available in `Graph`.}
305+
\cgalParamNEnd
306+
262307
\cgalParamNBegin{vertex_index_map}
263308
\cgalParamDescription{a property map associating to each vertex of `graph` a unique index}
264309
\cgalParamType{a class model of `WritablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
@@ -326,6 +371,8 @@ bool write_PLY(std::ostream& os,
326371

327372
bool has_vcolor = !is_default_parameter<CGAL_NP_CLASS, internal_np::vertex_color_map_t>::value;
328373
bool has_fcolor = !is_default_parameter<CGAL_NP_CLASS, internal_np::face_color_map_t>::value;
374+
constexpr bool has_vnormal = !is_default_parameter<CGAL_NP_CLASS, internal_np::vertex_normal_map_t>::value;
375+
329376
VIMap vim = CGAL::get_initialized_vertex_index_map(g, np);
330377
Vpm vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
331378
get_const_property_map(boost::vertex_point, g));
@@ -351,8 +398,20 @@ bool write_PLY(std::ostream& os,
351398
}
352399
}
353400

401+
354402
os << "element vertex " << vertices(g).size() << std::endl;
355-
internal::output_property_header(os, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
403+
if constexpr (std::is_same<typename Kernel_traits<Point_3>::Kernel::FT, float>::value)
404+
{
405+
internal::output_property_header(os, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
406+
}
407+
else
408+
{
409+
typedef typename Kernel_traits<Point_3>::Kernel K;
410+
typedef decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Point_3>())) Target_point;
411+
auto fvpm = CGAL::make_cartesian_converter_property_map<Target_point>(vpm);
412+
internal::output_property_header(os, make_ply_point_writer (fvpm));
413+
}
414+
356415
//if vcm is not default add v:color property
357416
if(has_vcolor)
358417
{
@@ -362,10 +421,30 @@ bool write_PLY(std::ostream& os,
362421
<< "property uchar alpha" << std::endl;
363422
}
364423

424+
if constexpr (has_vnormal)
425+
{
426+
auto vnm = get_parameter(np, internal_np::vertex_normal_map);
427+
typedef decltype(vnm) Normal_map;
428+
typedef typename Normal_map::value_type Vector_3;
429+
typedef typename Kernel_traits<Vector_3>::Kernel K;
430+
typedef typename K::FT FT;
431+
if constexpr (std::is_same<FT, float>::value)
432+
{
433+
internal::output_property_header(os, make_ply_normal_writer (CGAL::Identity_property_map<Vector_3>()));
434+
}
435+
else
436+
{
437+
typedef decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Vector_3>())) Target_vector;
438+
auto fvnm = CGAL::make_cartesian_converter_property_map<Target_vector>(vnm);
439+
internal::output_property_header(os, make_ply_normal_writer (fvnm));
440+
}
441+
}
442+
365443
os << "element face " << faces(g).size() << std::endl;
366444
internal::output_property_header(
367445
os, std::make_pair(CGAL::Identity_property_map<std::vector<std::size_t> >(),
368446
PLY_property<std::vector<int> >("vertex_indices")));
447+
369448
//if fcm is not default add f:color property
370449
if(has_fcolor)
371450
{
@@ -378,8 +457,42 @@ bool write_PLY(std::ostream& os,
378457

379458
for(vertex_descriptor vd : vertices(g))
380459
{
381-
const Point_3& p = get(vpm, vd);
382-
internal::output_properties(os, &p, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
460+
if constexpr (std::is_same<typename Kernel_traits<Point_3>::Kernel::FT, float>::value)
461+
{
462+
decltype(auto) p = get(vpm, vd);
463+
internal::output_properties(os, &p, make_ply_point_writer (CGAL::Identity_property_map<Point_3>()));
464+
}
465+
else
466+
{
467+
typedef typename Kernel_traits<Point_3>::Kernel K;
468+
typedef CGAL::cpp20::remove_cvref_t<decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Point_3>()))> Target_point;
469+
CGAL::Cartesian_converter_property_map<Target_point, Vpm> fvpm = CGAL::make_cartesian_converter_property_map<Target_point>(vpm);
470+
decltype(auto) fp = get(fvpm, vd);
471+
internal::output_properties(os, &fp, make_ply_point_writer (CGAL::Identity_property_map<Target_point>()));
472+
}
473+
474+
std::cout << "using generic writer" << std::endl;
475+
476+
if constexpr (!parameters::is_default_parameter<CGAL_NP_CLASS, internal_np::vertex_normal_map_t>::value)
477+
{
478+
auto vnm = get_parameter(np, internal_np::vertex_normal_map);
479+
typedef decltype(vnm) Normal_map;
480+
typedef typename Normal_map::value_type Vector_3;
481+
482+
if constexpr (std::is_same<typename Kernel_traits<Vector_3>::Kernel::FT, float>::value)
483+
{
484+
decltype(auto) vec = get(vnm,vd);
485+
internal::output_properties(os, &vec, make_ply_normal_writer (CGAL::Identity_property_map<Vector_3>()));
486+
}
487+
else
488+
{
489+
typedef typename Kernel_traits<Vector_3>::Kernel K;
490+
typedef CGAL::cpp20::remove_cvref_t<decltype(std::declval<CGAL::Cartesian_converter<K, Epick> >().operator()(std::declval<Vector_3>()))> Target_vector;
491+
auto fvnm = CGAL::make_cartesian_converter_property_map<Target_vector>(vnm);
492+
decltype(auto) fvec = get(fvnm, vd);
493+
internal::output_properties(os, &fvec, make_ply_normal_writer (CGAL::Identity_property_map<Target_vector>()));
494+
}
495+
}
383496
if(has_vcolor)
384497
{
385498
const CGAL::IO::Color& c = get(vcm, vd);
@@ -455,6 +568,15 @@ bool write_PLY(std::ostream& os, const Graph& g, const CGAL_NP_CLASS& np = param
455568
must be available in `Graph`.}
456569
\cgalParamNEnd
457570
571+
\cgalParamNBegin{vertex_normal_map}
572+
\cgalParamDescription{a property map associating normals to the vertices of `g`}
573+
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`
574+
as key type and `%Vector_3` as value type}
575+
\cgalParamDefault{`boost::get(CGAL::vertex_point, g)`}
576+
\cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
577+
must be available in `Graph`.}
578+
\cgalParamNEnd
579+
458580
\cgalParamNBegin{vertex_index_map}
459581
\cgalParamDescription{a property map associating to each vertex of `graph` a unique index between `0` and `num_vertices(graph) - 1`}
460582
\cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits<Graph>::%vertex_descriptor`

BGL/package_info/BGL/dependencies

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
Algebraic_foundations
2+
Arithmetic_kernel
23
BGL
34
Cartesian_kernel
45
Circulator
56
Distance_2
67
Distance_3
8+
Filtered_kernel
9+
Homogeneous_kernel
710
Hash_map
811
Installation
12+
Intersections_2
13+
Intersections_3
914
Interval_support
1015
Kernel_23
16+
Kernel_d
1117
Modular_arithmetic
1218
Number_types
1319
Profiling_tools
1420
Property_map
1521
Random_numbers
1622
STL_Extension
1723
Stream_support
24+
CGAL_Core

Lab/demo/Lab/Plugins/IO/PLY_io_plugin.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <CGAL/Three/CGAL_Lab_io_plugin_interface.h>
88
#include <CGAL/Surface_mesh/IO/PLY.h>
99
#include <CGAL/Three/Three.h>
10+
#include <CGAL/use.h>
1011

1112
#include <QInputDialog>
1213
#include <QApplication>
@@ -132,8 +133,9 @@ load(QFileInfo fileinfo, bool& ok, bool add_to_scene) {
132133
std::vector<CGAL::IO::Color> fcolors;
133134
std::vector<CGAL::IO::Color> vcolors;
134135

135-
if (!(CGAL::IO::read_PLY (in, points, polygons, fcolors, vcolors)))
136+
if (!(CGAL::IO::read_PLY (in, points, polygons, comments, fcolors, vcolors)))
136137
{
138+
CGAL_USE(comments);
137139
QApplication::restoreOverrideCursor();
138140
ok = false;
139141
return QList<Scene_item*>();

Property_map/include/CGAL/property_map.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,6 @@ struct Cartesian_converter_property_map
708708
{
709709
return CGAL::Cartesian_converter<K1, K2>()(get(pm.vpm, k));
710710
}
711-
712711
friend void put(Cartesian_converter_property_map<GeomObject, Vpm>& pm, const key_type& k, const value_type& v)
713712
{
714713
put(pm.vpm, k, CGAL::Cartesian_converter<K2, K1>()(v));

Stream_support/doc/Stream_support/IOstream.txt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,25 +94,25 @@ bool is_pretty(std::ios& s);
9494
\subsection IOstreamInput Input Operator
9595

9696
\cgal defines input operators for classes that are derived
97-
from the class `istream`. This allows to read from istreams
97+
from the class `std::istream`. This allows to read from istreams
9898
as `std::cin`, as well as from `std::istringstream` and `std::ifstream`.
9999
The input operator is defined for all classes in the \cgal `Kernel`.
100100
Let `is` be an input stream.
101101

102102
\code{.cpp}
103103
// Extracts object `c` from the stream `is`. Returns `is`.
104-
istream& operator>>(istream& is, Class c);
104+
istream& operator>>(istream& is, Class& c);
105105
\endcode
106106

107107
\code{.cpp}
108108
#include <iostream>
109109
#include <fstream>
110110

111-
#include <CGAL/Cartesian.h>
111+
#include <CGAL/Simple_cartesian.h>
112112
#include <CGAL/Segment_2.h>
113113

114-
typedef CGAL::Point_2< CGAL::Cartesian<double> > Point;
115-
typedef CGAL::Segment_2< CGAL::Cartesian<double> > Segment;
114+
typedef CGAL::Point_2< CGAL::Simple_cartesian<double> > Point;
115+
typedef CGAL::Segment_2< CGAL::Simple_cartesian<double> > Segment;
116116

117117
int
118118
main()
@@ -123,7 +123,7 @@ main()
123123
CGAL::IO::set_ascii_mode(std::cin);
124124
std::cin >> p >> q;
125125

126-
std::ifstream f("data.txt");
126+
std::ifstream f("data.txt", std::ios::binary);
127127
CGAL::IO::set_binary_mode(f);
128128
f >> s >> p;
129129

@@ -150,11 +150,11 @@ ostream& operator<<(ostream& os, Class c);
150150
#include <iostream>
151151
#include <fstream>
152152

153-
#include <CGAL/Cartesian.h>
153+
#include <CGAL/Simple_cartesian.h>
154154
#include <CGAL/Segment_2.h>
155155

156-
typedef CGAL::Point_2< CGAL::Cartesian<double> > Point;
157-
typedef CGAL::Segment_2< CGAL::Cartesian<double> > Segment;
156+
typedef CGAL::Point_2< CGAL::Simple_cartesian<double> > Point;
157+
typedef CGAL::Segment_2< CGAL::Simple_cartesian<double> > Segment;
158158

159159
int main()
160160
{

0 commit comments

Comments
 (0)