ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LineSetIO.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "LineSetIO.h"
9 
10 #include <FileSystem.h>
11 #include <Logging.h>
12 #include <rply.h>
13 
14 #include <unordered_map>
15 
16 namespace cloudViewer {
17 
18 namespace {
19 using namespace io;
20 
21 namespace ply_lineset_reader {
22 
23 struct PLYReaderState {
25  geometry::LineSet *lineset_ptr;
27  long vertex_num;
28  long line_index;
29  long line_num;
31  long color_num;
32 };
33 
34 int ReadVertexCallback(p_ply_argument argument) {
35  PLYReaderState *state_ptr;
36  long index;
37  ply_get_argument_user_data(argument, reinterpret_cast<void **>(&state_ptr),
38  &index);
39  if (state_ptr->vertex_index >= state_ptr->vertex_num) {
40  return 0; // some sanity check
41  }
42 
43  double value = ply_get_argument_value(argument);
44  state_ptr->lineset_ptr->points_[state_ptr->vertex_index](index) = value;
45  if (index == 2) { // reading 'z'
46  state_ptr->vertex_index++;
47  ++(*state_ptr->progress_bar);
48  }
49  return 1;
50 }
51 
52 int ReadLineCallback(p_ply_argument argument) {
53  PLYReaderState *state_ptr;
54  long index;
55  ply_get_argument_user_data(argument, reinterpret_cast<void **>(&state_ptr),
56  &index);
57  if (state_ptr->line_index >= state_ptr->line_num) {
58  return 0;
59  }
60 
61  double value = ply_get_argument_value(argument);
62  state_ptr->lineset_ptr->lines_[state_ptr->line_index](index) = int(value);
63  if (index == 1) { // reading 'vertex2'
64  state_ptr->line_index++;
65  ++(*state_ptr->progress_bar);
66  }
67  return 1;
68 }
69 
70 int ReadColorCallback(p_ply_argument argument) {
71  PLYReaderState *state_ptr;
72  long index;
73  ply_get_argument_user_data(argument, reinterpret_cast<void **>(&state_ptr),
74  &index);
75  if (state_ptr->color_index >= state_ptr->color_num) {
76  return 0;
77  }
78 
79  double value = ply_get_argument_value(argument);
80  state_ptr->lineset_ptr->colors_[state_ptr->color_index](index) =
81  value / 255.0;
82  if (index == 2) { // reading 'blue'
83  state_ptr->color_index++;
84  ++(*state_ptr->progress_bar);
85  }
86  return 1;
87 }
88 
89 } // namespace ply_lineset_reader
90 
91 static const std::unordered_map<
92  std::string,
93  std::function<bool(const std::string &, geometry::LineSet &, bool)>>
94  file_extension_to_lineset_read_function{
95  {"ply", ReadLineSetFromPLY},
96  };
97 
98 static const std::unordered_map<std::string,
99  std::function<bool(const std::string &,
100  const geometry::LineSet &,
101  const bool,
102  const bool,
103  const bool)>>
104  file_extension_to_lineset_write_function{
105  {"ply", WriteLineSetToPLY},
106  };
107 } // unnamed namespace
108 
109 namespace io {
110 using namespace cloudViewer;
111 std::shared_ptr<geometry::LineSet> CreateLineSetFromFile(
112  const std::string &filename,
113  const std::string &format,
114  bool print_progress) {
115  auto lineset = std::make_shared<geometry::LineSet>();
116  ReadLineSet(filename, *lineset, format, print_progress);
117  return lineset;
118 }
119 
120 bool ReadLineSet(const std::string &filename,
121  geometry::LineSet &lineset,
122  const std::string &format,
123  bool print_progress) {
124  std::string filename_ext;
125  if (format == "auto") {
126  filename_ext =
128  } else {
129  filename_ext = format;
130  }
131  if (filename_ext.empty()) {
133  "Read geometry::LineSet failed: unknown file extension.");
134  return false;
135  }
136  auto map_itr = file_extension_to_lineset_read_function.find(filename_ext);
137  if (map_itr == file_extension_to_lineset_read_function.end()) {
139  "Read geometry::LineSet failed: unknown file extension.");
140  return false;
141  }
142  bool success = map_itr->second(filename, lineset, print_progress);
143  utility::LogDebug("Read geometry::LineSet: {:d} vertices.",
144  (int)lineset.points_.size());
145  return success;
146 }
147 
148 bool WriteLineSet(const std::string &filename,
149  const geometry::LineSet &lineset,
150  bool write_ascii /* = false*/,
151  bool compressed /* = false*/,
152  bool print_progress) {
153  std::string filename_ext =
155  if (filename_ext.empty()) {
157  "Write geometry::LineSet failed: unknown file extension.");
158  return false;
159  }
160  auto map_itr = file_extension_to_lineset_write_function.find(filename_ext);
161  if (map_itr == file_extension_to_lineset_write_function.end()) {
163  "Write geometry::LineSet failed: unknown file extension.");
164  return false;
165  }
166  bool success = map_itr->second(filename, lineset, write_ascii, compressed,
167  print_progress);
168  utility::LogDebug("Write geometry::LineSet: {:d} vertices.",
169  (int)lineset.points_.size());
170  return success;
171 }
172 
173 bool ReadLineSetFromPLY(const std::string &filename,
174  geometry::LineSet &lineset,
175  bool print_progress) {
176  using namespace ply_lineset_reader;
177 
178  p_ply ply_file = ply_open(filename.c_str(), NULL, 0, NULL);
179  if (!ply_file) {
180  utility::LogWarning("Read PLY failed: unable to open file: {}",
181  filename);
182  return false;
183  }
184  if (!ply_read_header(ply_file)) {
185  utility::LogWarning("Read PLY failed: unable to parse header.");
186  ply_close(ply_file);
187  return false;
188  }
189 
190  PLYReaderState state;
191  state.lineset_ptr = &lineset;
192  state.vertex_num = ply_set_read_cb(ply_file, "vertex", "x",
193  ReadVertexCallback, &state, 0);
194  ply_set_read_cb(ply_file, "vertex", "y", ReadVertexCallback, &state, 1);
195  ply_set_read_cb(ply_file, "vertex", "z", ReadVertexCallback, &state, 2);
196 
197  state.line_num = ply_set_read_cb(ply_file, "edge", "vertex1",
198  ReadLineCallback, &state, 0);
199  ply_set_read_cb(ply_file, "edge", "vertex2", ReadLineCallback, &state, 1);
200 
201  state.color_num = ply_set_read_cb(ply_file, "edge", "red",
202  ReadColorCallback, &state, 0);
203  ply_set_read_cb(ply_file, "edge", "green", ReadColorCallback, &state, 1);
204  ply_set_read_cb(ply_file, "edge", "blue", ReadColorCallback, &state, 2);
205 
206  if (state.vertex_num <= 0) {
207  utility::LogWarning("Read PLY failed: number of vertex <= 0.");
208  ply_close(ply_file);
209  return false;
210  }
211  if (state.line_num <= 0) {
212  utility::LogWarning("Read PLY failed: number of edges <= 0.");
213  ply_close(ply_file);
214  return false;
215  }
216 
217  state.vertex_index = 0;
218  state.line_index = 0;
219  state.color_index = 0;
220 
221  lineset.clear();
222  lineset.points_.resize(state.vertex_num);
223  lineset.lines_.resize(state.line_num);
224  lineset.colors_.resize(state.color_num);
225 
227  state.vertex_num + state.line_num + state.color_num,
228  "Reading PLY: ", print_progress);
229  state.progress_bar = &progress_bar;
230 
231  if (!ply_read(ply_file)) {
232  utility::LogWarning("Read PLY failed: unable to read file: {}",
233  filename);
234  ply_close(ply_file);
235  return false;
236  }
237 
238  ply_close(ply_file);
239  return true;
240 }
241 
242 bool WriteLineSetToPLY(const std::string &filename,
243  const geometry::LineSet &lineset,
244  bool write_ascii /* = false*/,
245  bool compressed /* = false*/,
246  bool print_progress) {
247  if (lineset.IsEmpty()) {
248  utility::LogWarning("Write PLY failed: line set has 0 points.");
249  return false;
250  }
251  if (!lineset.HasLines()) {
252  utility::LogWarning("Write PLY failed: line set has 0 lines.");
253  return false;
254  }
255 
256  p_ply ply_file = ply_create(filename.c_str(),
257  write_ascii ? PLY_ASCII : PLY_LITTLE_ENDIAN,
258  NULL, 0, NULL);
259  if (!ply_file) {
260  utility::LogWarning("Write PLY failed: unable to open file: {}",
261  filename);
262  return false;
263  }
264  ply_add_comment(ply_file, "Created by cloudViewer");
265  ply_add_element(ply_file, "vertex",
266  static_cast<long>(lineset.points_.size()));
267  ply_add_property(ply_file, "x", PLY_DOUBLE, PLY_DOUBLE, PLY_DOUBLE);
268  ply_add_property(ply_file, "y", PLY_DOUBLE, PLY_DOUBLE, PLY_DOUBLE);
269  ply_add_property(ply_file, "z", PLY_DOUBLE, PLY_DOUBLE, PLY_DOUBLE);
270  ply_add_element(ply_file, "edge", static_cast<long>(lineset.lines_.size()));
271  ply_add_property(ply_file, "vertex1", PLY_INT, PLY_INT, PLY_INT);
272  ply_add_property(ply_file, "vertex2", PLY_INT, PLY_INT, PLY_INT);
273  if (lineset.HasColors()) {
274  ply_add_property(ply_file, "red", PLY_UCHAR, PLY_UCHAR, PLY_UCHAR);
275  ply_add_property(ply_file, "green", PLY_UCHAR, PLY_UCHAR, PLY_UCHAR);
276  ply_add_property(ply_file, "blue", PLY_UCHAR, PLY_UCHAR, PLY_UCHAR);
277  }
278  if (!ply_write_header(ply_file)) {
279  utility::LogWarning("Write PLY failed: unable to write header.");
280  ply_close(ply_file);
281  return false;
282  }
283 
285  static_cast<size_t>(lineset.points_.size() + lineset.lines_.size()),
286  "Writing PLY: ", print_progress);
287 
288  for (size_t i = 0; i < lineset.points_.size(); i++) {
289  const Eigen::Vector3d &point = lineset.points_[i];
290  ply_write(ply_file, point(0));
291  ply_write(ply_file, point(1));
292  ply_write(ply_file, point(2));
293  ++progress_bar;
294  }
295  bool printed_color_warning = false;
296  for (size_t i = 0; i < lineset.lines_.size(); i++) {
297  const Eigen::Vector2i &line = lineset.lines_[i];
298  ply_write(ply_file, line(0));
299  ply_write(ply_file, line(1));
300  if (lineset.HasColors()) {
301  const Eigen::Vector3d &color = lineset.colors_[i];
302  if (!printed_color_warning &&
303  (color(0) < 0 || color(0) > 1 || color(1) < 0 || color(1) > 1 ||
304  color(2) < 0 || color(2) > 1)) {
306  "Write Ply clamped color value to valid range");
307  printed_color_warning = true;
308  }
310  ply_write(ply_file, rgb(0));
311  ply_write(ply_file, rgb(1));
312  ply_write(ply_file, rgb(2));
313  }
314  ++progress_bar;
315  }
316 
317  ply_close(ply_file);
318  return true;
319 }
320 
321 } // namespace io
322 } // namespace cloudViewer
IsAscii write_ascii
Compressed compressed
std::string filename
filament::Texture::InternalFormat format
math::float4 color
long line_num
Definition: LineSetIO.cpp:29
cloudViewer::utility::ConsoleProgressBar * progress_bar
Definition: LineSetIO.cpp:24
long vertex_num
Definition: LineSetIO.cpp:27
geometry::LineSet * lineset_ptr
Definition: LineSetIO.cpp:25
long line_index
Definition: LineSetIO.cpp:28
long vertex_index
Definition: LineSetIO.cpp:26
long color_index
Definition: LineSetIO.cpp:30
long color_num
Definition: LineSetIO.cpp:31
#define NULL
LineSet define a sets of lines in 3D. A typical application is to display the point cloud corresponde...
Definition: LineSet.h:29
bool HasColors() const
Returns true if the objects lines contains colors.
Definition: LineSet.h:85
virtual bool IsEmpty() const override
Definition: LineSet.h:61
std::vector< Eigen::Vector3d > points_
Points coordinates.
Definition: LineSet.h:156
std::vector< Eigen::Vector3d > colors_
RGB colors of lines.
Definition: LineSet.h:160
bool HasLines() const
Returns true if the object contains lines.
Definition: LineSet.h:82
std::vector< Eigen::Vector2i > lines_
Lines denoted by the index of points forming the line.
Definition: LineSet.h:158
#define LogWarning(...)
Definition: Logging.h:72
#define LogDebug(...)
Definition: Logging.h:90
normal_z rgb
bool WriteLineSetToPLY(const std::string &filename, const geometry::LineSet &lineset, bool write_ascii=false, bool compressed=false, bool print_progress=false)
Definition: LineSetIO.cpp:242
bool WriteLineSet(const std::string &filename, const geometry::LineSet &lineset, bool write_ascii=false, bool compressed=false, bool print_progress=false)
Definition: LineSetIO.cpp:148
std::shared_ptr< geometry::LineSet > CreateLineSetFromFile(const std::string &filename, const std::string &format="auto", bool print_progress=false)
Definition: LineSetIO.cpp:111
bool ReadLineSet(const std::string &filename, geometry::LineSet &lineset, const std::string &format="auto", bool print_progress=false)
Definition: LineSetIO.cpp:120
bool ReadLineSetFromPLY(const std::string &filename, geometry::LineSet &lineset, bool print_progress=false)
Definition: LineSetIO.cpp:173
std::string GetFileExtensionInLowerCase(const std::string &filename)
Definition: FileSystem.cpp:281
Eigen::Vector3uint8 ColorToUint8(const Eigen::Vector3d &color)
Definition: Eigen.cpp:269
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 2, 1 > Vector2i
Definition: knncpp.h:29