cgv
Loading...
Searching...
No Matches
volume_io.cxx
1#include <cgv/base/base.h>
2#include "volume_io.h"
3#include <fstream>
4#include <stdio.h>
5#include <cgv/utils/file.h>
6#include <cgv/utils/scan.h>
7#include <cgv/utils/tokenizer.h>
8#include <cgv/media/image/image_reader.h>
9#include <cgv/media/image/image_writer.h>
10#include <cgv/media/video/video_reader.h>
11
12namespace cgv {
13 namespace media {
14 namespace volume {
15
16
17 volume_info::volume_info() : dimensions(0, 0, 0), extent(1, 1, 1), position(0, 0, 0), type_id(cgv::type::info::TI_UINT8), components(cgv::data::CF_L)
18 {
19 orientation.identity();
20 }
21 volume_info::volume_info(const volume& V, const std::string& _path)
22 {
23 path = _path;
26 dimensions = V.get_dimensions();
27 type_id = V.get_component_type();
28 components = V.get_format().get_standard_component_format();
29 extent = V.get_box().get_extent();
30 position = V.get_box().get_center();
31 orientation.identity();
32 }
33 size_t volume_info::get_data_size() const
34 {
35 return dimensions(0) * dimensions(1) * dimensions(2) * cgv::type::info::get_type_size(type_id);
36 }
37
38 bool read_vox(const std::string& file_name, volume& V, volume_info* info_ptr = 0);
39
40 bool read_qim_header(const std::string& file_name, volume_info& info);
41 bool read_qim(const std::string& file_name, volume& V, volume_info* info_ptr = 0);
42
43 bool read_tiff(const std::string& file_name, volume& V, volume_info* info_ptr = 0);
44
45 bool read_avi(const std::string& file_name, volume& V, volume_info* info_ptr = 0);
46
47
48 bool write_vox(const std::string& file_name, const volume& V);
49
50 bool write_qim_header(const std::string& file_name, const volume& V);
51 bool write_qim(const std::string& file_name, const volume& V);
52
53 bool write_tiff(const std::string& file_name, const volume& V, const std::string& options);
54
55
56 bool read_header(const std::string& file_name, volume_info& info, bool(*unknown_line_callback)(const std::string& line, const std::vector<cgv::utils::token>&, volume_info& info))
57 {
58 std::string ext = cgv::utils::to_upper(cgv::utils::file::get_extension(file_name));
59 if (ext == "HD")
60 return read_vox_header(file_name, info, unknown_line_callback);
61 if (ext == "QHA")
62 return read_qim_header(file_name, info);
63 return false;
64 }
65
66 bool read_volume(const std::string& file_name, volume& V, volume_info* info_ptr)
67 {
68 std::string ext = cgv::utils::to_upper(cgv::utils::file::get_extension(file_name));
69 if (ext == "VOX" || ext == "HD")
70 return read_vox(file_name, V, info_ptr);
71 if (ext == "QIM" || ext == "QHA")
72 return read_qim(file_name, V, info_ptr);
73 if (ext == "TIF" || ext == "TIFF")
74 return read_tiff(file_name, V, info_ptr);
75 if (ext == "AVI")
76 return read_avi(file_name, V, info_ptr);
77
78 std::cerr << "unsupported extension " << ext << std::endl;
79 return false;
80 }
81
82 bool write_header(const std::string& file_name, const volume& V)
83 {
84 std::string ext = cgv::utils::to_upper(cgv::utils::file::get_extension(file_name));
85 if (ext == "HD")
86 return write_vox_header(file_name, V);
87 if (ext == "QHA")
88 return write_qim_header(file_name, V);
89 return false;
90 }
91
92 bool write_volume(const std::string& file_name, const volume& V, const std::string& options)
93 {
94 std::string ext = cgv::utils::to_upper(cgv::utils::file::get_extension(file_name));
95 if (ext == "VOX" || ext == "HD")
96 return write_vox(file_name, V);
97 if (ext == "QIM" || ext == "QHA")
98 return write_qim(file_name, V);
99 if (ext == "TIF" || ext == "TIFF")
100 return write_tiff(file_name, V, options);
101
102 std::cerr << "unsupported extension " << ext << std::endl;
103 return false;
104 }
105
106 bool read_vox_header(const std::string& file_name, volume_info& info, bool (*unknown_line_callback)(const std::string& line, const std::vector<cgv::utils::token>&, volume_info& info))
107 {
108 std::ifstream is(file_name);
109 if (is.fail()) {
110 std::cerr << "could not open vox header " << file_name << std::endl;
111 return false;
112 }
113 while (!is.eof()) {
114 char buffer[500];
115 is.getline(buffer, 500);
116 std::string line(buffer);
117 cgv::utils::tokenizer t(line);
118 std::vector<cgv::utils::token> toks;
119 t.set_ws(" \t,x:");
120 t.set_skip("\"'", "\"'");
121 t.bite_all(toks);
122 bool success = false;
123 if (toks.size() >= 2) {
124 if (cgv::utils::to_upper(to_string(toks[0])) == "SIZE") {
125 int c;
126 for (c = 1; c < 4; ++c) {
127 if (!cgv::utils::is_integer(toks[c].begin, toks[c].end, info.dimensions(c - 1)))
128 break;
129 }
130 if (c == 4) {
131 success = true;
132 // check if value type is also given
133 if (toks.size() > 4) {
134 unsigned offset = 0;
135 std::string type_name = cgv::utils::to_upper(to_string(cgv::utils::token(toks[4].begin, toks.back().end)));
136 if (type_name.substr(0, 13) == "UNSIGNED BYTE") {
137 info.type_id = cgv::type::info::TI_UINT8;
138 offset = 14;
139 }
140 else if (type_name.substr(0, 14) == "UNSIGNED SHORT") {
141 info.type_id = cgv::type::info::TI_UINT16;
142 offset = 15;
143 }
144 else if (type_name.substr(0, 12) == "UNSIGNED INT") {
145 info.type_id = cgv::type::info::TI_UINT32;
146 offset = 13;
147 }
148 else if (type_name.substr(0, 11) == "SIGNED BYTE") {
149 info.type_id = cgv::type::info::TI_INT8;
150 offset = 12;
151 }
152 else if (type_name.substr(0, 12) == "SIGNED SHORT") {
153 info.type_id = cgv::type::info::TI_INT16;
154 offset = 13;
155 }
156 else if (type_name.substr(0, 10) == "SIGNED INT") {
157 info.type_id = cgv::type::info::TI_INT32;
158 offset = 11;
159 }
160 else if (type_name.substr(0, 5) == "FLOAT") {
161 info.type_id = cgv::type::info::TI_FLT32;
162 offset = 6;
163 }
164 else if (type_name.substr(0, 6) == "DOUBLE") {
165 info.type_id = cgv::type::info::TI_FLT64;
166 offset = 7;
167 }
168 else {
169 std::cerr << "unknown voxel type " << type_name << std::endl;
170 success = false;
171 }
172 if (success && offset < type_name.size()) {
173 std::string components = cgv::utils::to_upper(type_name.substr(offset));
174 if (components.substr(0, 9) == "LUMINANCE")
175 info.components = cgv::data::CF_L;
176 else if (components.substr(0, 9) == "INTENSITY")
177 info.components = cgv::data::CF_I;
178 else if (components.substr(0, 4) == "RGBA")
179 info.components = cgv::data::CF_RGBA;
180 else if (components.substr(0, 3) == "RGB")
181 info.components = cgv::data::CF_RGB;
182 else if (components.substr(0, 2) == "RG")
183 info.components = cgv::data::CF_RG;
184 else if (components.substr(0, 5) == "ALPHA")
185 info.components = cgv::data::CF_A;
186 }
187 }
188 }
189 }
190 else if (cgv::utils::to_upper(to_string(toks[0])) == "POSITION") {
191 int c;
192 for (c = 1; c < 4; ++c) {
193 double d;
194 if (cgv::utils::is_double(toks[c].begin, toks[c].end, d))
195 info.position(c - 1) = (float)d;
196 else
197 break;
198 }
199 if (c == 4)
200 success = true;
201 }
202 else if (cgv::utils::to_upper(to_string(toks[0])) == "ORIENTATION") {
203 int c;
204 for (c = 1; c < 10; ++c) {
205 double d;
206 if (cgv::utils::is_double(toks[c].begin, toks[c].end, d))
207 static_cast<cgv::math::fmat<volume::coord_type, 3, 3>::base_type&>(info.orientation)(c - 1) = (float)d;
208 else
209 break;
210 }
211 if (c == 10)
212 success = true;
213 }
214 else if (cgv::utils::to_upper(to_string(toks[0])) == "SCALING") {
215 int c;
216 for (c = 1; c < 4; ++c) {
217 double d;
218 if (cgv::utils::is_double(toks[c].begin, toks[c].end, d))
219 info.extent(c - 1) = (float)d;
220 else
221 break;
222 }
223 if (c == 4)
224 success = true;
225 }
226 else if (cgv::utils::to_upper(to_string(toks[0])) == "SPACING") {
227 int c;
228 for (c = 1; c < 4; ++c) {
229 double d;
230 if (cgv::utils::is_double(toks[c].begin, toks[c].end, d))
231 info.extent(c - 1) = (float)(d * info.dimensions(c - 1));
232 else
233 break;
234 }
235 if (c == 4)
236 success = true;
237 }
238 else if (cgv::utils::to_upper(to_string(toks[0])) == "PATH") {
239 info.path = to_string(toks[1]);
240 if (info.path.size() >= 2 && info.path.front() == info.path.back() &&
241 (info.path.front() == '"' || info.path.front() == '\''))
242 info.path = info.path.substr(1, info.path.size() - 2);
243 success = true;
244 }
245 }
246 if (!success) {
247 if (toks.size() > 0) {
248 if (unknown_line_callback && unknown_line_callback(line, toks, info)) {
249 success = true;
250 }
251 else {
252 std::cerr << "did not understand header line <" << line << ">!" << std::endl;
253 }
254 }
255 }
256 }
257 return true;
258 }
259
260 bool write_vox_header(const std::string& file_name, const volume_info& VI)
261 {
262 std::ofstream os(file_name);
263 if (os.fail()) {
264 std::cerr << "cannot open vox header " << file_name << " for writing." << std::endl;
265 return false;
266 }
267 os << "Size: " << VI.dimensions(0) << "x" << VI.dimensions(1) << "x" << VI.dimensions(2);
268 switch (VI.type_id) {
269 case cgv::type::info::TI_UINT8: os << " unsigned byte"; break;
270 case cgv::type::info::TI_UINT16: os << " unsigned short"; break;
271 case cgv::type::info::TI_UINT32: os << " unsigned int"; break;
272 case cgv::type::info::TI_INT8: os << " signed byte"; break;
273 case cgv::type::info::TI_INT16: os << " signed short"; break;
274 case cgv::type::info::TI_INT32: os << " signed int"; break;
275 case cgv::type::info::TI_FLT32: os << " float"; break;
276 case cgv::type::info::TI_FLT64: os << " double"; break;
277 }
278 switch (VI.components) {
279 case cgv::data::CF_L: os << " Luminance"; break;
280 case cgv::data::CF_I: os << " Intensity"; break;
281 case cgv::data::CF_RG: os << " RG"; break;
282 case cgv::data::CF_RGB: os << " RGB"; break;
283 case cgv::data::CF_RGBA: os << " RGBA"; break;
284 case cgv::data::CF_A: os << " Alpha"; break;
285 }
286 os << std::endl;
287 volume::extent_type scaling = VI.extent;
288 os << "Scaling: " << scaling(0)/VI.dimensions(0) << "x" << scaling(1)/VI.dimensions(1) << "x" << scaling(2)/VI.dimensions(2) << std::endl;
289 if (VI.position.length() > 1e-10)
290 os << "Position: " << VI.position(0) << ", " << VI.position(1) << ", " << VI.position(2) << std::endl;
291
293 I.identity();
294 if ((VI.orientation - I).length() > 1e-10) {
295 os << "Orientation: ";
296 for (int i = 0; i < 9; ++i) {
297 if (i > 0)
298 os << ", ";
299 os << reinterpret_cast<const cgv::math::fmat<volume::coord_type, 3, 3>::base_type&>(VI.orientation)(i);
300 }
301 os << std::endl;
302 }
303 if (!VI.path.empty())
304 os << "Path: \"" << VI.path << "\"" << std::endl;
305 return !os.fail();
306 }
307
308 // toggle endian
309 void toggle_volume_endian(volume& V)
310 {
311 std::size_t n = V.get_nr_voxels();
312 unsigned c = V.get_nr_components();
313 unsigned N = cgv::type::info::get_type_size(V.get_component_type());
314 if (N == 2) {
315 unsigned char* ptr = V.get_data_ptr<unsigned char>();
316 for (unsigned i = 0; i < n; ++i)
317 for (unsigned j = 0; j < c; ++j) {
318 std::swap(ptr[0], ptr[1]);
319 ptr += 2;
320 }
321 }
322 if (N == 4) {
323 unsigned char* ptr = V.get_data_ptr<unsigned char>();
324 for (unsigned i = 0; i < n; ++i)
325 for (unsigned j = 0; j < c; ++j) {
326 std::swap(ptr[0], ptr[3]);
327 std::swap(ptr[1], ptr[2]);
328 ptr += 4;
329 }
330 }
331 }
332
333 bool read_volume_binary(const std::string& file_name, const volume_info& info, volume& V, size_t offset)
334 {
335 // update volume data structure and reserve space
336 if (V.get_component_type() != info.type_id)
337 V.set_component_type(info.type_id);
338 if (V.get_component_format() != info.components)
339 V.set_component_format(info.components);
340 if (V.get_dimensions() != info.dimensions)
341 V.resize(info.dimensions);
342 if (V.get_extent() != info.extent)
343 V.ref_extent() = info.extent;
344
345 // open file and jump to offset
346 FILE* fp = fopen(file_name.c_str(), "rb");
347 if (!fp) {
348 std::cerr << "cannot open file " << file_name << std::endl;
349 return false;
350 }
351 if (offset > 0) {
352 fseek(fp, (long)offset, SEEK_SET);
353 }
354
355 // read data
356 std::size_t n = V.get_nr_voxels();
357 unsigned N = V.get_voxel_size();
358 std::size_t nr = fread(V.get_data_ptr<unsigned char>(), N, n, fp);
359 if (nr != n) {
360 std::cerr << "could not read the expected number " << n << " of voxels but only " << nr << std::endl;
361 fclose(fp);
362 return false;
363 }
364
365 // close and return success
366 fclose(fp);
367 return true;
368 }
369
370 bool read_vox(const std::string& file_name, volume& V, volume_info* info_ptr)
371 {
372 volume_info local_info;
373 volume_info& info = info_ptr ? *info_ptr : local_info;
374 if (!read_vox_header(cgv::utils::file::drop_extension(file_name) + ".hd", info))
375 return false;
376 return read_volume_binary(cgv::utils::file::drop_extension(file_name) + ".vox", info, V);
377 }
378
379 bool read_qim_header(const std::string& file_name, volume_info& info)
380 {
381 std::ifstream is(file_name);
382 if (is.fail()) {
383 std::cerr << "could not open qim header " << file_name << std::endl;
384 return false;
385 }
386 int nr_components;
387 volume::point_type c, x, y, z;
388 is >> nr_components >> c;
389 is >> info.dimensions(0) >> x;
390 is >> info.dimensions(1) >> y;
391 is >> info.dimensions(2) >> z;
392 info.extent = volume::extent_type(x.length(), y.length(), z.length());
393 if (nr_components != 1) {
394 std::cerr << "no support for more than one component in qim file yet" << std::endl;
395 exit(1);
396 }
397 return !is.fail();
398 }
399
400 bool read_qim(const std::string& file_name, volume& V, volume_info* info_ptr)
401 {
402 volume_info local_info;
403 volume_info& info = info_ptr ? *info_ptr : local_info;
404 if (!read_qim_header(cgv::utils::file::drop_extension(file_name) + ".qha", info))
405 return false;
406 return read_volume_binary(cgv::utils::file::drop_extension(file_name) + ".qim", info, V);
407 }
408
409 bool read_tiff(const std::string& file_name, volume& V, volume_info* info_ptr)
410 {
413 if (!ir.open(file_name)) {
414 std::cerr << "could not open tiff file " << file_name << std::endl;
415 return false;
416 }
417 int n = ir.get_nr_images();
418 V.get_format().set_component_format(df.get_component_format());
419 if (info_ptr) {
420 info_ptr->type_id = df.get_component_type();
421 info_ptr->components = df.get_standard_component_format();
422 }
423 volume::dimension_type size(int(df.get_width()), int(df.get_height()), n);
424 if (info_ptr) {
425 info_ptr->dimensions = size;
426 info_ptr->position.zeros();
427 info_ptr->orientation.identity();
428 }
429 V.resize(size);
430 V.ref_extent() = volume::point_type(1, 1, 1) * size / (float)cgv::math::max_value(size);
431 if (info_ptr)
432 info_ptr->extent = V.get_extent();
433 for (int i = 0; i < n; ++i) {
434 cgv::data::data_view dv(&df, V.get_slice_ptr<void>(i));
435 if (!ir.read_image(dv)) {
436 std::cerr << "could not read slice " << i << " of file " << file_name << std::endl;
437 return false;
438 }
439 }
440 ir.close();
441 return true;
442 }
443
444 bool read_avi(const std::string& file_name, volume& V, volume_info* info_ptr)
445 {
448 if (!vr.open(file_name)) {
449 std::cerr << "could not open avi file " << file_name << std::endl;
450 return false;
451 }
452 int nr_frames = vr.get<int>("nr_frames");
453 if (nr_frames == 0) {
454 std::cerr << "could not determine nr frames in avi file " << file_name << std::endl;
455 return false;
456 }
457 V.get_format().set_component_format(cgv::data::component_format(df.get_component_type(), cgv::data::CF_L));
458 if (info_ptr) {
459 info_ptr->type_id = V.get_format().get_component_type();
460 info_ptr->components = V.get_format().get_standard_component_format();
461 }
462 volume::dimension_type size(int(df.get_width()), int(df.get_height()), nr_frames);
463 if (info_ptr) {
464 info_ptr->dimensions = size;
465 info_ptr->position.zeros();
466 info_ptr->orientation.identity();
467 }
468 V.resize(size);
469 V.ref_extent() = volume::point_type(1, 1, 1) * size / (float)cgv::math::max_value(size);
470 if (info_ptr)
471 info_ptr->extent = V.get_extent();
472 cgv::data::data_view dv(&df);
473 unsigned char* src_ptr = dv.get_ptr<unsigned char>();
474 size_t n = df.get_width() * df.get_height();
475 for (int i = 0; i < nr_frames; ++i) {
476 if (!vr.read_frame(dv)) {
477 std::cerr << "could not read slice " << i << " of file " << file_name << std::endl;
478 return false;
479 }
480 unsigned char* dst_ptr = V.get_slice_ptr<unsigned char>(i);
481 for (size_t j = 0; j < n; ++j)
482 dst_ptr[j] = src_ptr[3 * j];
483 }
484 vr.close();
485 return true;
486 }
487
488 bool write_volume_binary(const std::string& file_name, const volume& V, size_t offset)
489 {
490 std::size_t n = V.get_nr_voxels();
491 unsigned N = V.get_voxel_size();
492 FILE* fp = fopen(file_name.c_str(), "wb");
493 if (!fp) {
494 std::cerr << "cannot open volume file " << file_name << " for write." << std::endl;
495 return false;
496 }
497 if (offset > 0) {
498 if (fseek(fp, (long)offset, SEEK_SET) != 0) {
499 std::cerr << "could not seek position " << offset << " in file " << file_name << std::endl;
500 fclose(fp);
501 return false;
502 }
503 }
504 std::size_t nr = fwrite(V.get_data_ptr<cgv::type::uint8_type>(), N, n, fp);
505 fclose(fp);
506 if (nr != n) {
507 std::cerr << "could not write the expected number " << n << " of voxels but only " << nr << std::endl;
508 return false;
509 }
510 std::cout << "write volume '" << file_name << "' of size " << V.get_dimensions() << " and scaling " << V.get_box().get_extent();
511 if (offset > 0)
512 std::cout << " at offset " << offset;
513 std::cout << std::endl;
514 return true;
515 }
516
517 bool write_vox(const std::string& file_name, const volume& V)
518 {
519 if (!write_vox_header(cgv::utils::file::drop_extension(file_name) + ".hd", volume_info(V)))
520 return false;
521 return write_volume_binary(cgv::utils::file::drop_extension(file_name) + ".vox", V);
522 }
523
524 bool write_qim_header(const std::string& file_name, const volume& V)
525 {
526 std::ofstream os(file_name);
527 if (os.fail()) {
528 std::cerr << "cannot open qim header " << file_name << " for writing." << std::endl;
529 return false;
530 }
531 os << V.get_nr_components() << " 0 0 0" << std::endl;
532 os << V.get_dimensions()(0) << " " << V.get_box().get_extent()(0) << " 0 0" << std::endl;
533 os << V.get_dimensions()(1) << " 0 " << V.get_box().get_extent()(1) << " 0" << std::endl;
534 os << V.get_dimensions()(2) << " 0 0 " << V.get_box().get_extent()(2) << std::endl;
535 return !os.fail();
536 }
537
538 bool write_qim(const std::string& file_name, const volume& V)
539 {
540 if (!write_vox_header(cgv::utils::file::drop_extension(file_name) + ".qha", V))
541 return false;
542 return write_volume_binary(cgv::utils::file::drop_extension(file_name) + ".qim", V);
543 }
544
545 bool write_tiff(const std::string& file_name, const volume& V, const std::string& options)
546 {
548 df.set_component_format(V.get_format().get_component_format());
549 df.set_width(V.get_dimensions()(0));
550 df.set_height(V.get_dimensions()(1));
552 iw.multi_set(options);
553 for (unsigned i = 0; i < (unsigned)(V.get_dimensions()(2)); ++i) {
554 cgv::data::const_data_view dv(&df, V.get_slice_ptr<void>(i));
555 if (!iw.write_image(dv)) {
556 std::cerr << "could not write slice " << i << " to tiff file " << file_name << std::endl;
557 return false;
558 }
559 }
560 return iw.close();
561 }
562
563 }
564 }
565}
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
the component format inherits the information of a packing_info and adds information on the component...
cgv::type::info::TypeId get_component_type() const
return the component type
ComponentFormat get_standard_component_format() const
return whether the component format is one of the standard formats
The const_data_view has the functionality of the data_view but uses a const pointer and therefore doe...
Definition data_view.h:221
A data_format describes a multidimensional data block of data entries.
Definition data_format.h:17
void set_component_format(const component_format &cf)
set component_format by simply assigning to a converted this pointer
void set_height(size_t _height)
set the resolution in the second dimension, add dimensions if necessary
void set_width(size_t _width)
set the resolution in the first dimension, add dimensions if necessary
size_t get_width() const
return the resolution in the first dimension, or 1 if not defined
size_t get_height() const
return the resolution in the second dimension, or 1 if not defined
const component_format & get_component_format() const
return the component_format info by simple conversion of the this pointer
the data view gives access to a data array of one, two, three or four dimensions.
Definition data_view.h:153
matrix of fixed size dimensions
Definition fmat.h:23
void identity()
set identity matrix
Definition fmat.h:240
the image reader chooses a specific reader automatically based on the extension of the given file nam...
the image writer chooses a specific writer automatically based on the extension of the given file nam...
the video reader chooses a specific reader automatically based on the extension of the given file nam...
the tokenizer allows to split text into tokens in a convenient way.
Definition tokenizer.h:68
ComponentFormat
define standard formats, which should be used to avoid wrong assignment of component names
@ CF_RGBA
color format with components R, G and B
@ CF_I
color format with luminance component L
@ CF_A
blue channel of color format
@ CF_L
alpha format
@ CF_RGB
color format with two components R and G
@ CF_RG
color format with intensity and alpha components: I and A
unsigned int get_type_size(TypeId tid)
function that returns the size of a type specified through TypeId
Definition type_id.cxx:18
TypeId
ids for the different types and type constructs
Definition type_id.h:12
@ TI_INT16
signed integer stored in 8 bits
Definition type_id.h:20
@ TI_INT8
boolean
Definition type_id.h:19
@ TI_INT32
signed integer stored in 16 bits
Definition type_id.h:21
@ TI_FLT32
floating point type stored in 16 bits
Definition type_id.h:28
@ TI_UINT32
unsigned integer stored in 16 bits
Definition type_id.h:25
@ TI_UINT8
signed integer stored in 64 bits
Definition type_id.h:23
@ TI_UINT16
unsigned integer stored in 8 bits
Definition type_id.h:24
@ TI_FLT64
floating point type stored in 32 bits
Definition type_id.h:29
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
bool is_integer(const char *begin, const char *end, int &value)
check if the text range (begin,end( defines an integer value. If yes, store the value in the passed r...
Definition scan.cxx:367
char to_upper(char c)
convert char to upper case
Definition scan.cxx:106
bool is_double(const char *begin, const char *end, double &value)
check if the text range (begin,end( defines a double value. If yes, store the value in the passed ref...
Definition scan.cxx:426
the cgv namespace
Definition print.h:11
the vr namespace for virtual reality support
Helper functions to process strings.
representation of a token in a text by two pointers begin and end, that point to the first character ...
Definition token.h:18