7 template<
typename Po
int>
8 void ply_importer::read_ascii_(Point* buffer, std::size_t n) {
10 std::vector<const char*> properties(number_of_properties_,
nullptr);
15 auto property = properties.begin();
17 bool last_space =
true;
18 for(
const char& c : line) {
19 bool space = std::isspace(c);
20 if(last_space == space)
continue;
21 else if(last_space) *(
property++) = &c;
25 read_ascii_point_(*buffer, properties.data());
31 template<
typename Po
int>
32 void ply_importer::read_binary_(Point* out, std::size_t n) {
33 std::streamsize length = n * vertex_length_;
34 std::unique_ptr<byte[]> buffer(
new byte[length]);
35 file_.read(reinterpret_cast<char*>(buffer.get()), length);
37 byte* buffer_end = buffer.get() + length;
38 for(
byte* in = buffer.get(); in != buffer_end; in += vertex_length_, ++out)
39 read_binary_point_(*out, in);
44 T ply_importer::read_binary_property_(
const property& prop,
byte* data)
const {
45 std::size_t sz = property_type_size_(prop.type);
49 case int8:
return static_cast<T
>( *
reinterpret_cast<const std::int8_t*
>(data) );
50 case uint8:
return static_cast<T
>( *
reinterpret_cast<const std::uint8_t*
>(data) );
51 case int16:
return static_cast<T
>( *
reinterpret_cast<const std::int16_t*
>(data) );
52 case uint16:
return static_cast<T
>( *
reinterpret_cast<const std::uint16_t*
>(data) );
53 case int32:
return static_cast<T
>( *
reinterpret_cast<const std::int32_t*
>(data) );
54 case uint32:
return static_cast<T
>( *
reinterpret_cast<const std::uint32_t*
>(data) );
58 case float32:
return static_cast<T
>( *
reinterpret_cast<const float*
>(data) );
59 case float64:
return static_cast<T
>( *
reinterpret_cast<const double*
>(data) );
67 ply_importer::property_type ply_importer::identify_property_type_(
const std::string& nm) {
68 if(nm ==
"char" || nm ==
"int8")
return int8;
69 else if(nm ==
"uchar" || nm ==
"uint8")
return uint8;
70 else if(nm ==
"short" || nm ==
"int16")
return int16;
71 else if(nm ==
"ushort" || nm ==
"uint16")
return uint16;
72 else if(nm ==
"int" || nm ==
"int32")
return int32;
73 else if(nm ==
"uint" || nm ==
"uint32")
return uint32;
74 else if(nm ==
"float" || nm ==
"float32")
return float32;
75 else if(nm ==
"double" || nm ==
"float64")
return float64;
76 else if(nm ==
"list")
return list;
77 else throw ply_importer_error(std::string(
"Unknown property type ") + nm);
81 ply_importer::property* ply_importer::identify_property_(
const std::string& nm_orig) {
83 if(nm ==
"x")
return &x_;
84 else if(nm ==
"y")
return &y_;
85 else if(nm ==
"z")
return &z_;
86 else if(nm ==
"nx")
return &nx_;
87 else if(nm ==
"ny")
return &ny_;
88 else if(nm ==
"nz")
return &nz_;
89 else if(nm ==
"r" || nm ==
"red")
return &r_;
90 else if(nm ==
"g" || nm ==
"green")
return &g_;
91 else if(nm ==
"b" || nm ==
"blue")
return &b_;
92 else if(nm ==
"weight")
return &w_;
97 void ply_importer::read_header_() {
100 std::ifstream::pos_type data_start = 0;
101 std::size_t number_of_elements_before_vertex_data = 0;
102 std::ifstream::off_type vertex_data_start_offset = 0;
104 std::ptrdiff_t vertex_property_index = 0;
105 std::ptrdiff_t vertex_property_data_offset = 0;
110 if(line !=
"ply")
throw ply_importer_error(
"Not PLY file (First line not 'ply')");
114 if(line ==
"format binary_little_endian 1.0") format_ = binary_little_endian;
115 else if(line ==
"format binary_big_endian 1.0") format_ = binary_big_endian;
116 else if(line ==
"format ascii 1.0") format_ = ascii;
117 else throw ply_importer_error(
"Unknown PLY format: " + line);
123 enum { before_vertex_definition, within_vertex_definition, after_vertex_definition } state = before_vertex_definition;
124 std::size_t number_of_elements = 0;
128 if(line.substr(0, 8) ==
"comment ")
continue;
129 if(line.substr(0, 9) ==
"obj_info ")
continue;
131 if(line.substr(0, 8) ==
"element ") {
132 auto pos = line.find(
' ', 8);
133 std::string element = line.substr(8, pos-8);
134 number_of_elements = stoul(line.substr(pos + 1));
135 if(element ==
"vertex") {
137 if(state != before_vertex_definition)
throw ply_importer_error(
"More than one vertex element definitions.");
138 state = within_vertex_definition;
139 number_of_vertices_ = number_of_elements;
140 }
else if(state == within_vertex_definition) {
142 state = after_vertex_definition;
143 }
else if(state == before_vertex_definition) {
146 number_of_elements_before_vertex_data += number_of_elements;
149 }
else if(line.substr(0, 9) ==
"property ") {
150 if(state == after_vertex_definition)
continue;
153 auto pos = line.find(
' ', 9);
154 std::string name = line.substr(pos + 1);
155 property_type type = identify_property_type_(line.substr(9, pos-9));
156 if(type == list)
throw ply_importer_error(
"List property type not supported.");
157 std::size_t type_size = property_type_size_(type);
159 if(
is_binary() && state == before_vertex_definition) {
161 vertex_data_start_offset += number_of_elements * type_size;
163 }
else if(state == within_vertex_definition) {
165 property* prop = identify_property_(name);
170 prop->offset = vertex_property_data_offset;
171 prop->index = vertex_property_index;
174 vertex_property_data_offset += type_size;
175 ++vertex_property_index;
178 }
else if(line.substr(0, 10) ==
"end_header") {
179 if(state == before_vertex_definition)
throw ply_importer_error(
"No vertex element definition.");
180 data_start = file_.tellg();
182 }
else if(! std::all_of(line.begin(), line.end(), isspace)) {
184 throw ply_importer_error(
"Invalid line encountered: " + line);
186 }
while(! data_start);
188 if(!x_ || !y_ || !z_)
throw ply_importer_error(
"X, Y, Z coordinate properties not defined.");
189 has_rgb_ = (r_ && g_ && b_);
190 has_normal_ = (nx_ && ny_ && nz_);
191 has_weight_ = (bool)w_;
193 vertex_length_ = vertex_property_data_offset;
194 number_of_properties_ = vertex_property_index;
198 vertex_data_start_ = data_start + vertex_data_start_offset;
201 skip_lines_(number_of_elements_before_vertex_data);
202 vertex_data_start_ = file_.tellg();
208 file_.seekg(vertex_data_start_);
209 current_element_ = 0;
214 file_(filename, std::ios_base::in | std::ios_base::binary),
221 std::size_t ply_importer::property_type_size_(property_type t) {
223 case int8:
case uint8:
return 1;
224 case int16:
case uint16:
return 2;
225 case int32:
case uint32:
return 4;
226 case float32:
return 4;
227 case float64:
return 8;
233 void ply_importer::read_ascii_point_(
point_xyz& pt,
const char* props[])
const {
235 strtof(props[x_.index],
nullptr),
236 strtof(props[y_.index],
nullptr),
237 strtof(props[z_.index],
nullptr)
243 void ply_importer::read_ascii_point_(
point_full& pt,
const char* props[])
const {
245 strtof(props[x_.index],
nullptr),
246 strtof(props[y_.index],
nullptr),
247 strtof(props[z_.index],
nullptr)
250 strtol(props[r_.index],
nullptr, 10),
251 strtol(props[g_.index],
nullptr, 10),
252 strtol(props[b_.index],
nullptr, 10)
257 void ply_importer::read_binary_point_(
point_xyz& pt,
byte* data)
const {
259 read_binary_property_<float>(x_, data),
260 read_binary_property_<float>(y_, data),
261 read_binary_property_<float>(z_, data)
266 void ply_importer::read_binary_point_(
point_full& pt,
byte* data)
const {
268 read_binary_property_<float>(x_, data),
269 read_binary_property_<float>(y_, data),
270 read_binary_property_<float>(z_, data)
273 read_binary_property_<std::uint8_t>(r_, data),
274 read_binary_property_<std::uint8_t>(g_, data),
275 read_binary_property_<std::uint8_t>(b_, data)
281 if(current_element_ + n > number_of_vertices_)
284 if(
is_ascii()) read_ascii_(buffer, n);
285 else read_binary_(buffer, n);
287 current_element_ += n;
292 if(current_element_ + n > number_of_vertices_)
295 if(
is_ascii()) read_ascii_(buffer, n);
296 else read_binary_(buffer, n);
298 current_element_ += n;
303 return current_element_;
308 return number_of_vertices_;
ply_importer(const std::string &filename, line_delimitor ld=line_delimitor::unknown)
std::ptrdiff_t tell() const
const bool host_has_iec559_float
void read(point_xyz *, std::size_t sz)
line_delimitor detect_line_delimitor(std::istream &str, std::size_t max_offset)
Detects line delimitor used in given file.
std::string to_lower(const std::string &s_orig)
void flip_endianness(byte *data, std::size_t sz)