Search code examples
cgal

How to use write_ply_with_properties() with Point_set_3


I have a CGAL::Point_set_3 point set with point normal and color. I would like to save all properties to a PLY file, using write_ply_with_properties() function. My goal is to make the full version work (see code below), but even the simple version doesn't compile, with the same error as the full version.

I work on Linux with CGAL release 4.14 and gcc 7.4.0.

Here is the code:

#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Point_set_3.h>
#include <CGAL/Point_set_3/IO.h>

#include <tuple> // for std::tie
#include <fstream>


typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef Kernel::Point_3 Point;
typedef Kernel::Vector_3 Vector;
typedef CGAL::Point_set_3<Point> Point_set;


int main(int argc, char*argv[])
{
  Point_set points;
  points.insert(Point(1., 2., 3.));
  points.insert(Point(4., 5., 6.));

  // add normal map
  points.add_normal_map();
  auto normal_map = points.normal_map();

  // add color map
  typedef Point_set::Property_map< Vector > ColorMap;
  bool success = false;
  ColorMap color_map;
  std::tie(color_map, success) =
      points.add_property_map< Vector >("color");
  assert(success);

  // populate normal and color map
  for(auto it = points.begin(); it != points.end(); ++it)
  {
    normal_map[*it] = Vector(10., 11., 12.);
    color_map[*it] = Vector(20., 21., 22.);
  }

  std::ofstream out("out.ply");
#if 1
  // simple version
  if(!out || !CGAL::write_ply_points_with_properties(
                  out,
                  points.points(), // const PointRange
                  CGAL::make_ply_point_writer(points.point_map())))
#else
  // full version
  if(!out || !CGAL::write_ply_points_with_properties(
                  out,
                  points.points(), // const PointRange
                  CGAL::make_ply_point_writer(points.point_map()),
                  CGAL::make_ply_normal_writer(points.normal_map()),
                  std::make_tuple(color_map,
                                  CGAL::PLY_property< double >("red"),
                                  CGAL::PLY_property< double >("green"),
                                  CGAL::PLY_property< double >("blue"))))
#endif
  {
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

The compilation error is:

...
/usr/include/boost/property_map/property_map.hpp:303:54: error: no match for ‘operator[]’ (operand types are ‘const CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Property_map<CGAL::Point_3<CGAL::Epick> >’ and ‘const CGAL::Point_3<CGAL::Epick>’)
     Reference v = static_cast<const PropertyMap&>(pa)[k];
CGAL-4.14/include/CGAL/Surface_mesh/Properties.h:567:15: note: candidate: CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::reference CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::operator[](const I&) [with I = CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Index; T = CGAL::Point_3<CGAL::Epick>; CRTP_derived_class = CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Property_map<CGAL::Point_3<CGAL::Epick> >; CGAL::Properties::Property_map_base<I, T, CRTP_derived_class>::reference = CGAL::Point_3<CGAL::Epick>&]
     reference operator[](const I& i)
               ^~~~~~~~
CGAL-4.14/include/CGAL/Surface_mesh/Properties.h:567:15: note:   no known conversion for argument 1 from ‘const CGAL::Point_3<CGAL::Epick>’ to ‘const CGAL::Point_set_3<CGAL::Point_3<CGAL::Epick> >::Index&’

How can I fix it?


Solution

  • The problem in your code is that you are using the method points() of CGAL::Point_set_3 which returns a range of points of type CGAL::Point_set_3::Point_range, whereas the property maps that you use (points.point_map(), etc.) are directly applied to a type CGAL::Point_set_3.

    So you should simply call the write_ply_points_with_properties() on points, not on points.points().

    Note also that if you store your colors on simple types (for example, using three Point_set_3 properties typed unsigned char), you can take advantage of the function CGAL::write_ply_point_set() that will automatically write all the simply-typed properties it finds, which makes it quite straightforward to use (just do CGAL::write_ply_point_set(out, points) and you're done).

    One last thing that is really a detail not related to your problem, but you should avoid using the CGAL::Vector_3 for storing anything else than an actual geometric 3D vector (like colors in your case). That makes your code harder to read and is also quite an ineffective way to store colors if they are encoded as integer values between 0 and 255 (which is what unsigned char is for).