23
#include "PreCompiled.h"
31
#include <boost/algorithm/string.hpp>
32
#include <boost/lexical_cast.hpp>
33
#include <boost/math/special_functions/fpclassify.hpp>
34
#include <boost/regex.hpp>
37
#include <Base/Console.h>
38
#include <Base/Converter.h>
39
#include <Base/Exception.h>
40
#include <Base/FileInfo.h>
41
#include <Base/Sequencer.h>
42
#include <Base/Stream.h>
44
#include "PointsAlgos.h"
48
using namespace Points;
50
void PointsAlgos::Load(PointKernel& points, const char* FileName)
52
Base::FileInfo File(FileName);
55
if (!File.isReadable()) {
56
throw Base::FileException("File to load not existing or not readable", FileName);
59
if (File.hasExtension("asc")) {
60
LoadAscii(points, FileName);
63
throw Base::RuntimeError("Unknown ending");
67
void PointsAlgos::LoadAscii(PointKernel& points, const char* FileName)
69
boost::regex rx("^\\s*([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
70
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)"
71
"\\s+([-+]?[0-9]*)\\.?([0-9]+([eE][-+]?[0-9]+)?)\\s*$");
80
Base::FileInfo fi(FileName);
82
Base::ifstream tmp_str(fi, std::ios::in);
85
while (std::getline(tmp_str, line)) {
90
points.resize(LineCnt);
92
Base::SequencerLauncher seq("Loading points...", LineCnt);
95
Base::ifstream file(fi, std::ios::in);
100
while (std::getline(file, line)) {
101
if (boost::regex_match(line.c_str(), what, rx)) {
102
pt.x = std::atof(what[1].first);
103
pt.y = std::atof(what[4].first);
104
pt.z = std::atof(what[7].first);
106
points.setPoint(LineCnt, pt);
114
throw Base::BadFormatError("Reading in points failed.");
120
if (LineCnt < (int)points.size()) {
121
points.erase(LineCnt, points.size());
127
Reader::Reader() = default;
129
Reader::~Reader() = default;
138
const PointKernel& Reader::getPoints() const
143
bool Reader::hasProperties() const
145
return (hasIntensities() || hasColors() || hasNormals());
148
const std::vector<float>& Reader::getIntensities() const
153
bool Reader::hasIntensities() const
155
return (!intensity.empty());
158
const std::vector<App::Color>& Reader::getColors() const
163
bool Reader::hasColors() const
165
return (!colors.empty());
168
const std::vector<Base::Vector3f>& Reader::getNormals() const
173
bool Reader::hasNormals() const
175
return (!normals.empty());
178
bool Reader::isStructured() const
180
return (width > 1 && height > 1);
183
int Reader::getWidth() const
188
int Reader::getHeight() const
195
AscReader::AscReader() = default;
197
void AscReader::read(const std::string& filename)
199
points.load(filename.c_str());
201
this->width = points.size();
211
Converter() = default;
212
virtual ~Converter() = default;
213
virtual std::string toString(double) const = 0;
214
virtual double toDouble(Base::InputStream&) const = 0;
215
virtual int getSizeOf() const = 0;
217
Converter(const Converter&) = delete;
218
Converter(Converter&&) = delete;
219
Converter& operator=(const Converter&) = delete;
220
Converter& operator=(Converter&&) = delete;
223
class ConverterT: public Converter
226
std::string toString(double f) const override
228
T c = static_cast<T>(f);
229
std::ostringstream oss;
231
oss.setf(std::ostringstream::showpoint);
235
double toDouble(Base::InputStream& str) const override
239
return static_cast<double>(c);
241
int getSizeOf() const override
247
using ConverterPtr = std::shared_ptr<Converter>;
249
class DataStreambuf: public std::streambuf
252
explicit DataStreambuf(const std::vector<char>& data)
254
, _end(int(data.size()))
256
~DataStreambuf() override = default;
259
int_type uflow() override
262
return traits_type::eof();
265
return static_cast<DataStreambuf::int_type>(_buffer[_cur++]) & 0x000000ff;
267
int_type underflow() override
270
return traits_type::eof();
273
return static_cast<DataStreambuf::int_type>(_buffer[_cur]) & 0x000000ff;
275
int_type pbackfail(int_type ch) override
277
if (_cur == _beg || (ch != traits_type::eof() && ch != _buffer[_cur - 1])) {
278
return traits_type::eof();
281
return static_cast<DataStreambuf::int_type>(_buffer[--_cur]) & 0x000000ff;
283
std::streamsize showmanyc() override
287
pos_type seekoff(std::streambuf::off_type off,
288
std::ios_base::seekdir way,
289
std::ios_base::openmode mode = std::ios::in | std::ios::out) override
293
if (way == std::ios_base::beg) {
296
else if (way == std::ios_base::end) {
299
else if (way == std::ios_base::cur) {
304
return traits_type::eof();
307
if (((p_pos + off) > _end) || ((p_pos + off) < _beg)) {
308
return traits_type::eof();
313
return ((p_pos + off) - _beg);
315
pos_type seekpos(std::streambuf::pos_type pos,
316
std::ios_base::openmode which = std::ios::in | std::ios::out) override
319
return seekoff(pos, std::ios_base::beg);
323
DataStreambuf(const DataStreambuf&) = delete;
324
DataStreambuf(DataStreambuf&&) = delete;
325
DataStreambuf& operator=(const DataStreambuf&) = delete;
326
DataStreambuf& operator=(DataStreambuf&&) = delete;
329
const std::vector<char>& _buffer;
330
int _beg {0}, _end {0}, _cur {0};
336
lzfDecompress(const void* const in_data, unsigned int in_len, void* out_data, unsigned int out_len)
338
unsigned char const* ip = static_cast<const unsigned char*>(in_data);
339
unsigned char* op = static_cast<unsigned char*>(out_data);
340
unsigned char const* const in_end = ip + in_len;
341
unsigned char* const out_end = op + out_len;
344
unsigned int ctrl = *ip++;
347
if (ctrl < (1 << 5)) {
350
if (op + ctrl > out_end) {
356
if (ip + ctrl > in_end) {
460
unsigned int len = ctrl >> 5;
462
unsigned char* ref = op - ((ctrl & 0x1f) << 8) - 1;
479
if (op + len + 2 > out_end) {
484
if (ref < static_cast<unsigned char*>(out_data)) {
493
if (op >= ref + len) {
495
memcpy(op, ref, len);
539
} while (ip < in_end);
541
return (static_cast<unsigned int>(op - static_cast<unsigned char*>(out_data)));
546
PlyReader::PlyReader() = default;
548
void PlyReader::read(const std::string& filename)
552
Base::FileInfo fi(filename);
553
Base::ifstream inp(fi, std::ios::in | std::ios::binary);
556
std::vector<std::string> fields;
557
std::vector<std::string> types;
558
std::vector<int> sizes;
559
std::size_t offset = 0;
560
Eigen::Index numPoints = Eigen::Index(readHeader(inp, format, offset, fields, types, sizes));
562
this->width = numPoints;
565
Eigen::MatrixXd data(numPoints, fields.size());
566
if (format == "ascii") {
567
readAscii(inp, offset, data);
569
else if (format == "binary_little_endian") {
570
readBinary(false, inp, offset, types, sizes, data);
572
else if (format == "binary_big_endian") {
573
readBinary(true, inp, offset, types, sizes, data);
576
std::vector<std::string>::iterator it;
577
Eigen::Index max_size = std::numeric_limits<Eigen::Index>::max();
580
Eigen::Index x = max_size;
581
it = std::find(fields.begin(), fields.end(), "x");
582
if (it != fields.end()) {
583
x = std::distance(fields.begin(), it);
587
Eigen::Index y = max_size;
588
it = std::find(fields.begin(), fields.end(), "y");
589
if (it != fields.end()) {
590
y = std::distance(fields.begin(), it);
594
Eigen::Index z = max_size;
595
it = std::find(fields.begin(), fields.end(), "z");
596
if (it != fields.end()) {
597
z = std::distance(fields.begin(), it);
601
Eigen::Index normal_x = max_size;
602
it = std::find(fields.begin(), fields.end(), "normal_x");
603
if (it == fields.end()) {
604
it = std::find(fields.begin(), fields.end(), "nx");
606
if (it != fields.end()) {
607
normal_x = std::distance(fields.begin(), it);
611
Eigen::Index normal_y = max_size;
612
it = std::find(fields.begin(), fields.end(), "normal_y");
613
if (it == fields.end()) {
614
it = std::find(fields.begin(), fields.end(), "ny");
616
if (it != fields.end()) {
617
normal_y = std::distance(fields.begin(), it);
621
Eigen::Index normal_z = max_size;
622
it = std::find(fields.begin(), fields.end(), "normal_z");
623
if (it == fields.end()) {
624
it = std::find(fields.begin(), fields.end(), "nz");
626
if (it != fields.end()) {
627
normal_z = std::distance(fields.begin(), it);
631
Eigen::Index greyvalue = max_size;
632
it = std::find(fields.begin(), fields.end(), "intensity");
633
if (it != fields.end()) {
634
greyvalue = std::distance(fields.begin(), it);
638
Eigen::Index red = max_size;
639
Eigen::Index green = max_size;
640
Eigen::Index blue = max_size;
641
Eigen::Index alpha = max_size;
642
it = std::find(fields.begin(), fields.end(), "red");
643
if (it != fields.end()) {
644
red = std::distance(fields.begin(), it);
647
it = std::find(fields.begin(), fields.end(), "green");
648
if (it != fields.end()) {
649
green = std::distance(fields.begin(), it);
652
it = std::find(fields.begin(), fields.end(), "blue");
653
if (it != fields.end()) {
654
blue = std::distance(fields.begin(), it);
657
it = std::find(fields.begin(), fields.end(), "alpha");
658
if (it != fields.end()) {
659
alpha = std::distance(fields.begin(), it);
663
bool hasData = (x != max_size && y != max_size && z != max_size);
664
bool hasNormal = (normal_x != max_size && normal_y != max_size && normal_z != max_size);
665
bool hasIntensity = (greyvalue != max_size);
666
bool hasColor = (red != max_size && green != max_size && blue != max_size);
669
points.reserve(numPoints);
670
for (Eigen::Index i = 0; i < numPoints; i++) {
671
points.push_back(Base::Vector3d(data(i, x), data(i, y), data(i, z)));
675
if (hasData && hasNormal) {
676
normals.reserve(numPoints);
677
for (Eigen::Index i = 0; i < numPoints; i++) {
678
normals.emplace_back(data(i, normal_x), data(i, normal_y), data(i, normal_z));
682
if (hasData && hasIntensity) {
683
intensity.reserve(numPoints);
684
for (Eigen::Index i = 0; i < numPoints; i++) {
685
intensity.push_back(static_cast<float>(data(i, greyvalue)));
689
if (hasData && hasColor) {
690
colors.reserve(numPoints);
692
if (types[red] == "uchar") {
693
for (Eigen::Index i = 0; i < numPoints; i++) {
694
float r = static_cast<float>(data(i, red));
695
float g = static_cast<float>(data(i, green));
696
float b = static_cast<float>(data(i, blue));
697
if (alpha != max_size) {
698
a = static_cast<float>(data(i, alpha));
700
colors.emplace_back(static_cast<float>(r) / 255.0F,
701
static_cast<float>(g) / 255.0F,
702
static_cast<float>(b) / 255.0F,
703
static_cast<float>(a) / 255.0F);
706
else if (types[red] == "float") {
707
for (Eigen::Index i = 0; i < numPoints; i++) {
708
float r = static_cast<float>(data(i, red));
709
float g = static_cast<float>(data(i, green));
710
float b = static_cast<float>(data(i, blue));
711
if (alpha != max_size) {
712
a = static_cast<float>(data(i, alpha));
714
colors.emplace_back(r, g, b, a);
720
std::size_t PlyReader::readHeader(std::istream& in,
723
std::vector<std::string>& fields,
724
std::vector<std::string>& types,
725
std::vector<int>& sizes)
729
std::vector<std::string> list;
730
std::size_t numPoints = 0;
732
std::vector<std::pair<std::size_t, std::size_t>> count_props;
738
if (!in || (ply[0] != 'p') || (ply[1] != 'l') || (ply[2] != 'y')) {
739
throw Base::BadFormatError("Not a ply file");
742
while (std::getline(in, line)) {
749
boost::split(list, line, boost::is_any_of("\t\r "), boost::token_compress_on);
751
std::istringstream str(line);
752
str.imbue(std::locale::classic());
756
if (kw == "format") {
757
if (list.size() != 3) {
758
throw Base::BadFormatError("Not a valid ply file");
761
std::string format_string = list[1];
762
std::string version = list[2];
764
if (format_string == "ascii") {
765
format = format_string;
767
else if (format_string == "binary_big_endian") {
768
format = format_string;
770
else if (format_string == "binary_little_endian") {
771
format = format_string;
775
throw Base::BadFormatError("Wrong format version");
777
if (version != "1.0") {
779
throw Base::BadFormatError("Wrong version number");
782
else if (kw == "element") {
783
if (list.size() != 3) {
784
throw Base::BadFormatError("Not a valid ply file");
787
std::string name = list[1];
788
std::size_t count = boost::lexical_cast<std::size_t>(list[2]);
789
if (name == "vertex") {
795
if (numPoints == 0) {
796
count_props.emplace_back(count, 0);
804
else if (kw == "property") {
805
if (list.size() < 3) {
806
throw Base::BadFormatError("Not a valid ply file");
809
std::string name = list.back();
810
std::list<std::string> number;
811
if (list[1] == "list") {
812
number.insert(number.end(), list.begin(), list.end());
818
number.push_back(list[1]);
821
for (const auto& it : number) {
823
if (it == "char" || it == "int8") {
826
else if (it == "uchar" || it == "uint8") {
829
else if (it == "short" || it == "int16") {
832
else if (it == "ushort" || it == "uint16") {
835
else if (it == "int" || it == "int32") {
838
else if (it == "uint" || it == "uint32") {
841
else if (it == "float" || it == "float32") {
844
else if (it == "double" || it == "float64") {
849
throw Base::BadFormatError("Not a valid number type");
852
if (element == "vertex") {
854
fields.push_back(name);
856
sizes.push_back(size);
858
else if (!count_props.empty()) {
859
count_props.back().second += size;
863
else if (kw == "end_header") {
868
if (fields.size() != sizes.size() || fields.size() != types.size()) {
869
throw Base::BadFormatError("");
873
if (format == "ascii") {
875
std::vector<std::pair<std::size_t, std::size_t>>::iterator it;
876
for (it = count_props.begin(); it != count_props.end(); ++it) {
881
std::vector<std::pair<std::size_t, std::size_t>>::iterator it;
882
for (it = count_props.begin(); it != count_props.end(); ++it) {
883
offset += it->first * it->second;
890
void PlyReader::readAscii(std::istream& inp, std::size_t offset, Eigen::MatrixXd& data)
893
Eigen::Index row = 0;
894
Eigen::Index numPoints = Eigen::Index(data.rows());
895
Eigen::Index numFields = Eigen::Index(data.cols());
896
std::vector<std::string> list;
897
while (std::getline(inp, line) && row < numPoints) {
909
boost::split(list, line, boost::is_any_of("\t\r "), boost::token_compress_on);
911
std::istringstream str(line);
913
Eigen::Index size = Eigen::Index(list.size());
914
for (Eigen::Index col = 0; col < size && col < numFields; col++) {
915
double value = boost::lexical_cast<double>(list[col]);
916
data(row, col) = value;
923
void PlyReader::readBinary(bool swapByteOrder,
926
const std::vector<std::string>& types,
927
const std::vector<int>& sizes,
928
Eigen::MatrixXd& data)
930
Eigen::Index numPoints = data.rows();
931
Eigen::Index numFields = data.cols();
934
ConverterPtr convert_float32(new ConverterT<float>);
935
ConverterPtr convert_float64(new ConverterT<double>);
936
ConverterPtr convert_int8(new ConverterT<int8_t>);
937
ConverterPtr convert_uint8(new ConverterT<uint8_t>);
938
ConverterPtr convert_int16(new ConverterT<int16_t>);
939
ConverterPtr convert_uint16(new ConverterT<uint16_t>);
940
ConverterPtr convert_int32(new ConverterT<int32_t>);
941
ConverterPtr convert_uint32(new ConverterT<uint32_t>);
943
std::vector<ConverterPtr> converters;
944
for (Eigen::Index j = 0; j < numFields; j++) {
945
const std::string& t = types[j];
948
if (t == "char" || t == "int8") {
949
converters.push_back(convert_int8);
951
else if (t == "uchar" || t == "uint8") {
952
converters.push_back(convert_uint8);
955
throw Base::BadFormatError("Unexpected type");
959
if (t == "short" || t == "int16") {
960
converters.push_back(convert_int16);
962
else if (t == "ushort" || t == "uint16") {
963
converters.push_back(convert_uint16);
966
throw Base::BadFormatError("Unexpected type");
970
if (t == "int" || t == "int32") {
971
converters.push_back(convert_int32);
973
else if (t == "uint" || t == "uint32") {
974
converters.push_back(convert_uint32);
976
else if (t == "float" || t == "float32") {
977
converters.push_back(convert_float32);
980
throw Base::BadFormatError("Unexpected type");
984
if (t == "double" || t == "float64") {
985
converters.push_back(convert_float64);
988
throw Base::BadFormatError("Unexpected type");
992
throw Base::BadFormatError("Unexpected type");
995
neededSize += converters.back()->getSizeOf();
998
std::streamoff ulSize = 0;
999
std::streamoff ulCurr = 0;
1000
std::streambuf* buf = inp.rdbuf();
1002
ulCurr = buf->pubseekoff(static_cast<std::streamoff>(offset), std::ios::cur, std::ios::in);
1003
ulSize = buf->pubseekoff(0, std::ios::end, std::ios::in);
1004
buf->pubseekoff(ulCurr, std::ios::beg, std::ios::in);
1005
if (ulCurr + neededSize * static_cast<std::streamoff>(numPoints) > ulSize) {
1006
throw Base::BadFormatError("File expects too many elements");
1010
Base::InputStream str(inp);
1011
str.setByteOrder(swapByteOrder ? Base::Stream::BigEndian : Base::Stream::LittleEndian);
1012
for (Eigen::Index i = 0; i < numPoints; i++) {
1013
for (Eigen::Index j = 0; j < numFields; j++) {
1014
double value = converters[j]->toDouble(str);
1022
PcdReader::PcdReader() = default;
1024
void PcdReader::read(const std::string& filename)
1030
Base::FileInfo fi(filename);
1031
Base::ifstream inp(fi, std::ios::in | std::ios::binary);
1034
std::vector<std::string> fields;
1035
std::vector<std::string> types;
1036
std::vector<int> sizes;
1037
Eigen::Index numPoints = Eigen::Index(readHeader(inp, format, fields, types, sizes));
1039
Eigen::MatrixXd data(numPoints, fields.size());
1040
if (format == "ascii") {
1041
readAscii(inp, data);
1043
else if (format == "binary") {
1044
readBinary(false, inp, types, sizes, data);
1046
else if (format == "binary_compressed") {
1049
Base::InputStream str(inp);
1052
std::vector<char> compressed(c);
1053
inp.read(compressed.data(), c);
1054
std::vector<char> uncompressed(u);
1055
if (lzfDecompress(compressed.data(), c, uncompressed.data(), u) == u) {
1056
DataStreambuf ibuf(uncompressed);
1057
std::istream istr(nullptr);
1059
readBinary(true, istr, types, sizes, data);
1062
throw Base::BadFormatError("Failed to decompress binary data");
1066
std::vector<std::string>::iterator it;
1067
Eigen::Index max_size = std::numeric_limits<Eigen::Index>::max();
1070
Eigen::Index x = max_size;
1071
it = std::find(fields.begin(), fields.end(), "x");
1072
if (it != fields.end()) {
1073
x = std::distance(fields.begin(), it);
1077
Eigen::Index y = max_size;
1078
it = std::find(fields.begin(), fields.end(), "y");
1079
if (it != fields.end()) {
1080
y = std::distance(fields.begin(), it);
1084
Eigen::Index z = max_size;
1085
it = std::find(fields.begin(), fields.end(), "z");
1086
if (it != fields.end()) {
1087
z = std::distance(fields.begin(), it);
1091
Eigen::Index normal_x = max_size;
1092
it = std::find(fields.begin(), fields.end(), "normal_x");
1093
if (it == fields.end()) {
1094
it = std::find(fields.begin(), fields.end(), "nx");
1096
if (it != fields.end()) {
1097
normal_x = std::distance(fields.begin(), it);
1101
Eigen::Index normal_y = max_size;
1102
it = std::find(fields.begin(), fields.end(), "normal_y");
1103
if (it == fields.end()) {
1104
it = std::find(fields.begin(), fields.end(), "ny");
1106
if (it != fields.end()) {
1107
normal_y = std::distance(fields.begin(), it);
1111
Eigen::Index normal_z = max_size;
1112
it = std::find(fields.begin(), fields.end(), "normal_z");
1113
if (it == fields.end()) {
1114
it = std::find(fields.begin(), fields.end(), "nz");
1116
if (it != fields.end()) {
1117
normal_z = std::distance(fields.begin(), it);
1121
Eigen::Index greyvalue = max_size;
1122
it = std::find(fields.begin(), fields.end(), "intensity");
1123
if (it != fields.end()) {
1124
greyvalue = std::distance(fields.begin(), it);
1128
Eigen::Index rgba = max_size;
1129
it = std::find(fields.begin(), fields.end(), "rgb");
1130
if (it == fields.end()) {
1131
it = std::find(fields.begin(), fields.end(), "rgba");
1133
if (it != fields.end()) {
1134
rgba = std::distance(fields.begin(), it);
1138
bool hasData = (x != max_size && y != max_size && z != max_size);
1139
bool hasNormal = (normal_x != max_size && normal_y != max_size && normal_z != max_size);
1140
bool hasIntensity = (greyvalue != max_size);
1141
bool hasColor = (rgba != max_size);
1144
points.reserve(numPoints);
1145
for (Eigen::Index i = 0; i < numPoints; i++) {
1146
points.push_back(Base::Vector3d(data(i, x), data(i, y), data(i, z)));
1150
if (hasData && hasNormal) {
1151
normals.reserve(numPoints);
1152
for (Eigen::Index i = 0; i < numPoints; i++) {
1153
normals.emplace_back(data(i, normal_x), data(i, normal_y), data(i, normal_z));
1157
if (hasData && hasIntensity) {
1158
intensity.reserve(numPoints);
1159
for (Eigen::Index i = 0; i < numPoints; i++) {
1160
intensity.push_back(data(i, greyvalue));
1164
if (hasData && hasColor) {
1165
colors.reserve(numPoints);
1166
if (types[rgba] == "U") {
1167
for (Eigen::Index i = 0; i < numPoints; i++) {
1168
uint32_t packed = static_cast<uint32_t>(data(i, rgba));
1170
col.setPackedARGB(packed);
1171
colors.emplace_back(col);
1174
else if (types[rgba] == "F") {
1175
static_assert(sizeof(float) == sizeof(uint32_t),
1176
"float and uint32_t have different sizes");
1177
for (Eigen::Index i = 0; i < numPoints; i++) {
1178
float f = static_cast<float>(data(i, rgba));
1180
std::memcpy(&packed, &f, sizeof(packed));
1182
col.setPackedARGB(packed);
1183
colors.emplace_back(col);
1189
std::size_t PcdReader::readHeader(std::istream& in,
1190
std::string& format,
1191
std::vector<std::string>& fields,
1192
std::vector<std::string>& types,
1193
std::vector<int>& sizes)
1196
std::vector<std::string> counts;
1197
std::vector<std::string> list;
1198
std::size_t points = 0;
1200
while (std::getline(in, line)) {
1207
boost::split(list, line, boost::is_any_of("\t\r "), boost::token_compress_on);
1209
std::istringstream str(line);
1210
str.imbue(std::locale::classic());
1214
if (kw == "FIELDS") {
1215
for (std::size_t i = 1; i < list.size(); i++) {
1216
fields.push_back(list[i]);
1219
else if (kw == "SIZE") {
1220
for (std::size_t i = 1; i < list.size(); i++) {
1221
sizes.push_back(boost::lexical_cast<int>(list[i]));
1224
else if (kw == "TYPE") {
1225
for (std::size_t i = 1; i < list.size(); i++) {
1226
types.push_back(list[i]);
1229
else if (kw == "COUNT") {
1230
for (std::size_t i = 1; i < list.size(); i++) {
1231
counts.push_back(list[i]);
1234
else if (kw == "WIDTH") {
1235
str >> std::ws >> this->width;
1237
else if (kw == "HEIGHT") {
1238
str >> std::ws >> this->height;
1240
else if (kw == "POINTS") {
1241
str >> std::ws >> points;
1243
else if (kw == "DATA") {
1244
str >> std::ws >> format;
1249
std::size_t w = static_cast<std::size_t>(this->width);
1250
std::size_t h = static_cast<std::size_t>(this->height);
1251
std::size_t size = w * h;
1252
if (fields.size() != sizes.size() || fields.size() != types.size()
1253
|| fields.size() != counts.size() || points != size) {
1254
throw Base::BadFormatError("");
1260
void PcdReader::readAscii(std::istream& inp, Eigen::MatrixXd& data)
1263
Eigen::Index row = 0;
1264
Eigen::Index numPoints = data.rows();
1265
Eigen::Index numFields = data.cols();
1266
std::vector<std::string> list;
1267
while (std::getline(inp, line) && row < numPoints) {
1274
boost::split(list, line, boost::is_any_of("\t\r "), boost::token_compress_on);
1276
std::istringstream str(line);
1278
Eigen::Index size = Eigen::Index(list.size());
1279
for (Eigen::Index col = 0; col < size && col < numFields; col++) {
1280
double value = boost::lexical_cast<double>(list[col]);
1281
data(row, col) = value;
1288
void PcdReader::readBinary(bool transpose,
1290
const std::vector<std::string>& types,
1291
const std::vector<int>& sizes,
1292
Eigen::MatrixXd& data)
1294
Eigen::Index numPoints = data.rows();
1295
Eigen::Index numFields = data.cols();
1298
ConverterPtr convert_float32(new ConverterT<float>);
1299
ConverterPtr convert_float64(new ConverterT<double>);
1300
ConverterPtr convert_int8(new ConverterT<int8_t>);
1301
ConverterPtr convert_uint8(new ConverterT<uint8_t>);
1302
ConverterPtr convert_int16(new ConverterT<int16_t>);
1303
ConverterPtr convert_uint16(new ConverterT<uint16_t>);
1304
ConverterPtr convert_int32(new ConverterT<int32_t>);
1305
ConverterPtr convert_uint32(new ConverterT<uint32_t>);
1307
std::vector<ConverterPtr> converters;
1308
for (Eigen::Index j = 0; j < numFields; j++) {
1309
char t = types[j][0];
1313
converters.push_back(convert_int8);
1315
else if (t == 'U') {
1316
converters.push_back(convert_uint8);
1319
throw Base::BadFormatError("Unexpected type");
1324
converters.push_back(convert_int16);
1326
else if (t == 'U') {
1327
converters.push_back(convert_uint16);
1330
throw Base::BadFormatError("Unexpected type");
1335
converters.push_back(convert_int32);
1337
else if (t == 'U') {
1338
converters.push_back(convert_uint32);
1340
else if (t == 'F') {
1341
converters.push_back(convert_float32);
1344
throw Base::BadFormatError("Unexpected type");
1349
converters.push_back(convert_float64);
1352
throw Base::BadFormatError("Unexpected type");
1356
throw Base::BadFormatError("Unexpected type");
1359
neededSize += converters.back()->getSizeOf();
1362
std::streamoff ulSize = 0;
1363
std::streamoff ulCurr = 0;
1364
std::streambuf* buf = inp.rdbuf();
1366
ulCurr = buf->pubseekoff(0, std::ios::cur, std::ios::in);
1367
ulSize = buf->pubseekoff(0, std::ios::end, std::ios::in);
1368
buf->pubseekoff(ulCurr, std::ios::beg, std::ios::in);
1369
if (ulCurr + neededSize * static_cast<std::streamoff>(numPoints) > ulSize) {
1370
throw Base::BadFormatError("File expects too many elements");
1374
Base::InputStream str(inp);
1376
for (Eigen::Index j = 0; j < numFields; j++) {
1377
for (Eigen::Index i = 0; i < numPoints; i++) {
1378
double value = converters[j]->toDouble(str);
1384
for (Eigen::Index i = 0; i < numPoints; i++) {
1385
for (Eigen::Index j = 0; j < numFields; j++) {
1386
double value = converters[j]->toDouble(str);
1400
E57ReaderImp(const std::string& filename, bool color, bool state, double distance)
1401
: imfi(filename, "r")
1403
, checkState {state}
1404
, minDistance {distance}
1409
e57::StructureNode root = imfi.root();
1410
if (root.isDefined("data3D")) {
1411
e57::VectorNode data3D(root.get("data3D"));
1416
std::vector<App::Color> getColors() const
1421
std::vector<float> getItensity() const
1426
const PointKernel& getPoints() const
1431
const std::vector<Base::Vector3f>& getNormals() const
1437
void readData3D(const e57::VectorNode& data3D)
1439
for (int child = 0; child < data3D.childCount(); ++child) {
1440
e57::StructureNode scan_data(data3D.get(child));
1441
Base::Placement plm;
1442
bool hasPlacement = getPlacement(scan_data, plm);
1444
e57::CompressedVectorNode cvn(scan_data.get("points"));
1445
e57::StructureNode prototype(cvn.prototype());
1446
Proto proto = readProto(prototype);
1447
processProto(cvn, proto, hasPlacement, plm);
1454
bool inv_state = false;
1455
unsigned cnt_xyz = 0;
1456
unsigned cnt_nor = 0;
1457
unsigned cnt_rgb = 0;
1459
std::vector<double> xData;
1460
std::vector<double> yData;
1461
std::vector<double> zData;
1463
std::vector<double> xNormal;
1464
std::vector<double> yNormal;
1465
std::vector<double> zNormal;
1467
std::vector<unsigned> redData;
1468
std::vector<unsigned> greenData;
1469
std::vector<unsigned> blueData;
1471
std::vector<double> intensity;
1472
std::vector<int64_t> state;
1473
std::vector<int64_t> nil;
1475
std::vector<e57::SourceDestBuffer> sdb;
1478
Proto readProto(const e57::StructureNode& prototype)
1481
resizeArrays(proto);
1483
for (int i = 0; i < prototype.childCount(); ++i) {
1484
e57::Node node(prototype.get(i));
1485
if ((node.type() == e57::E57_FLOAT) || (node.type() == e57::E57_SCALED_INTEGER)) {
1486
if (readCartesian(node, proto)) {}
1487
else if (readNormal(node, proto)) {}
1488
else if (readItensity(node, proto)) {}
1490
readOther(node, proto);
1493
else if (node.type() == e57::E57_INTEGER) {
1494
if (readColor(node, proto)) {}
1495
else if (readCartesianInvalidState(node, proto)) {}
1497
readOther(node, proto);
1505
bool readCartesian(const e57::Node& node, Proto& proto)
1507
if (node.elementName() == "cartesianX") {
1510
.emplace_back(imfi, node.elementName(), proto.xData.data(), buf_size, true, true
1515
else if (node.elementName() == "cartesianY") {
1518
.emplace_back(imfi, node.elementName(), proto.yData.data(), buf_size, true, true
1523
else if (node.elementName() == "cartesianZ") {
1526
.emplace_back(imfi, node.elementName(), proto.zData.data(), buf_size, true, true
1535
bool readNormal(const e57::Node& node, Proto& proto)
1537
if (node.elementName() == "nor:normalX") {
1540
.emplace_back(imfi, node.elementName(), proto.xNormal.data(), buf_size, true, true
1545
else if (node.elementName() == "nor:normalY") {
1548
.emplace_back(imfi, node.elementName(), proto.yNormal.data(), buf_size, true, true
1553
else if (node.elementName() == "nor:normalZ") {
1556
.emplace_back(imfi, node.elementName(), proto.zNormal.data(), buf_size, true, true
1565
bool readCartesianInvalidState(const e57::Node& node, Proto& proto)
1567
if (node.elementName() == "cartesianInvalidState") {
1568
proto.inv_state = true;
1570
.emplace_back(imfi, node.elementName(), proto.state.data(), buf_size, true, true
1579
bool readColor(const e57::Node& node, Proto& proto)
1581
if (node.elementName() == "colorRed") {
1584
.emplace_back(imfi, node.elementName(), proto.redData.data(), buf_size, true, true
1589
if (node.elementName() == "colorGreen") {
1592
.emplace_back(imfi, node.elementName(), proto.greenData.data(), buf_size, true, true
1597
if (node.elementName() == "colorBlue") {
1600
.emplace_back(imfi, node.elementName(), proto.blueData.data(), buf_size, true, true
1609
bool readItensity(const e57::Node& node, Proto& proto)
1611
if (node.elementName() == "intensity") {
1614
.emplace_back(imfi, node.elementName(), proto.intensity.data(), buf_size, true, true
1623
void readOther(const e57::Node& node, Proto& proto)
1625
proto.sdb.emplace_back(imfi, node.elementName(), proto.nil.data(), buf_size, true, true
1630
void processProto(e57::CompressedVectorNode& cvn,
1633
const Base::Placement& plm)
1635
if (proto.cnt_xyz != 3) {
1636
throw Base::BadFormatError("Missing channels xyz");
1639
unsigned cnt_pts = 0;
1640
Base::Vector3d pt, last;
1641
e57::CompressedVectorReader cvr(cvn.reader(proto.sdb));
1642
bool hasColor = (proto.cnt_rgb == 3) && useColor;
1643
bool hasItensity = proto.inty;
1644
bool hasNormal = (proto.cnt_nor == 3);
1645
bool hasState = proto.inv_state && checkState;
1646
bool filter = false;
1648
while ((count = cvr.read())) {
1649
for (size_t i = 0; i < count; ++i) {
1652
if (proto.state[i] != 0) {
1657
pt = getCoord(proto, i, hasPlacement, plm);
1659
if ((!filter) && (cnt_pts > 0)) {
1660
if (Base::Distance(last, pt) < minDistance) {
1666
points.push_back(pt);
1669
colors.push_back(getColor(proto, i));
1672
intensity.push_back(proto.intensity[i]);
1675
normals.push_back(getNormal(proto, i, hasPlacement, plm.getRotation()));
1683
getCoord(const Proto& proto, size_t index, bool hasPlacement, const Base::Placement& plm) const
1686
pt.x = proto.xData[index];
1687
pt.y = proto.yData[index];
1688
pt.z = proto.zData[index];
1690
plm.multVec(pt, pt);
1696
getNormal(const Proto& proto, size_t index, bool hasPlacement, const Base::Rotation& rot) const
1699
pt.x = proto.xNormal[index];
1700
pt.y = proto.yNormal[index];
1701
pt.z = proto.zNormal[index];
1703
rot.multVec(pt, pt);
1708
App::Color getColor(const Proto& proto, size_t index) const
1711
c.r = static_cast<float>(proto.redData[index]) / 255.0F;
1712
c.g = static_cast<float>(proto.greenData[index]) / 255.0F;
1713
c.b = static_cast<float>(proto.blueData[index]) / 255.0F;
1717
void resizeArrays(Proto& proto)
1719
proto.xData.resize(buf_size);
1720
proto.yData.resize(buf_size);
1721
proto.zData.resize(buf_size);
1723
proto.xNormal.resize(buf_size);
1724
proto.yNormal.resize(buf_size);
1725
proto.zNormal.resize(buf_size);
1727
proto.redData.resize(buf_size);
1728
proto.greenData.resize(buf_size);
1729
proto.blueData.resize(buf_size);
1731
proto.intensity.resize(buf_size);
1732
proto.state.resize(buf_size);
1733
proto.nil.resize(buf_size);
1736
bool getPlacement(const e57::StructureNode& scan_data, Base::Placement& plm) const
1738
bool hasPlacement {false};
1739
if (scan_data.isDefined("pose")) {
1740
e57::StructureNode pose(scan_data.get("pose"));
1741
if (pose.isDefined("rotation")) {
1742
e57::StructureNode rotNode(pose.get("rotation"));
1743
double quaternion[4];
1744
quaternion[0] = e57::FloatNode(rotNode.get("x")).value();
1745
quaternion[1] = e57::FloatNode(rotNode.get("y")).value();
1746
quaternion[2] = e57::FloatNode(rotNode.get("z")).value();
1747
quaternion[3] = e57::FloatNode(rotNode.get("w")).value();
1748
Base::Rotation rotate(quaternion);
1749
plm.setRotation(rotate);
1750
hasPlacement = true;
1752
if (pose.isDefined("translation")) {
1753
Base::Vector3d move;
1754
e57::StructureNode transNode(pose.get("translation"));
1755
move.x = e57::FloatNode(transNode.get("x")).value();
1756
move.y = e57::FloatNode(transNode.get("y")).value();
1757
move.z = e57::FloatNode(transNode.get("z")).value();
1758
plm.setPosition(move);
1759
hasPlacement = true;
1763
return hasPlacement;
1767
e57::ImageFile imfi;
1771
const size_t buf_size = 1024;
1772
std::vector<App::Color> colors;
1773
std::vector<float> intensity;
1775
std::vector<Base::Vector3f> normals;
1779
E57Reader::E57Reader(bool Color, bool State, double Distance)
1781
, checkState {State}
1782
, minDistance {Distance}
1785
void E57Reader::read(const std::string& filename)
1788
E57ReaderImp reader(filename, useColor, checkState, minDistance);
1790
points = reader.getPoints();
1791
normals = reader.getNormals();
1792
colors = reader.getColors();
1793
intensity = reader.getItensity();
1794
width = points.size();
1797
catch (const Base::BadFormatError&) {
1801
throw Base::BadFormatError("Reading E57 file failed");
1807
Writer::Writer(const PointKernel& p)
1809
, width(int(p.size()))
1813
Writer::~Writer() = default;
1815
void Writer::setIntensities(const std::vector<float>& i)
1820
void Writer::setColors(const std::vector<App::Color>& c)
1825
void Writer::setNormals(const std::vector<Base::Vector3f>& n)
1830
void Writer::setWidth(int w)
1835
void Writer::setHeight(int h)
1840
void Writer::setPlacement(const Base::Placement& p)
1847
AscWriter::AscWriter(const PointKernel& p)
1851
void AscWriter::write(const std::string& filename)
1853
if (placement.isIdentity()) {
1854
points.save(filename.c_str());
1857
PointKernel copy = points;
1858
copy.transformGeometry(placement.toMatrix());
1859
copy.save(filename.c_str());
1865
PlyWriter::PlyWriter(const PointKernel& p)
1869
void PlyWriter::write(const std::string& filename)
1871
std::list<std::string> properties;
1872
properties.emplace_back("float x");
1873
properties.emplace_back("float y");
1874
properties.emplace_back("float z");
1876
ConverterPtr convert_float(new ConverterT<float>);
1877
ConverterPtr convert_uint(new ConverterT<uint32_t>);
1879
std::vector<ConverterPtr> converters;
1880
converters.push_back(convert_float);
1881
converters.push_back(convert_float);
1882
converters.push_back(convert_float);
1884
bool hasIntensity = (intensity.size() == points.size());
1885
bool hasColors = (colors.size() == points.size());
1886
bool hasNormals = (normals.size() == points.size());
1889
properties.emplace_back("float nx");
1890
properties.emplace_back("float ny");
1891
properties.emplace_back("float nz");
1892
converters.push_back(convert_float);
1893
converters.push_back(convert_float);
1894
converters.push_back(convert_float);
1898
properties.emplace_back("uchar red");
1899
properties.emplace_back("uchar green");
1900
properties.emplace_back("uchar blue");
1901
properties.emplace_back("uchar alpha");
1902
converters.push_back(convert_uint);
1903
converters.push_back(convert_uint);
1904
converters.push_back(convert_uint);
1905
converters.push_back(convert_uint);
1909
properties.emplace_back("float intensity");
1910
converters.push_back(convert_float);
1913
Eigen::Index numPoints = Eigen::Index(points.size());
1914
Eigen::Index numValid = 0;
1915
const std::vector<Base::Vector3f>& pts = points.getBasicPoints();
1916
for (Eigen::Index i = 0; i < numPoints; i++) {
1917
const Base::Vector3f& p = pts[i];
1918
if (!boost::math::isnan(p.x) && !boost::math::isnan(p.y) && !boost::math::isnan(p.z)) {
1923
Eigen::MatrixXf data(numPoints, properties.size());
1925
if (placement.isIdentity()) {
1926
for (Eigen::Index i = 0; i < numPoints; i++) {
1927
data(i, 0) = pts[i].x;
1928
data(i, 1) = pts[i].y;
1929
data(i, 2) = pts[i].z;
1934
for (Eigen::Index i = 0; i < numPoints; i++) {
1935
tmp = Base::convertTo<Base::Vector3d>(pts[i]);
1936
placement.multVec(tmp, tmp);
1937
data(i, 0) = static_cast<float>(tmp.x);
1938
data(i, 1) = static_cast<float>(tmp.y);
1939
data(i, 2) = static_cast<float>(tmp.z);
1943
Eigen::Index col = 3;
1945
Eigen::Index col0 = col;
1946
Eigen::Index col1 = col + 1;
1947
Eigen::Index col2 = col + 2;
1948
Base::Rotation rot = placement.getRotation();
1949
if (rot.isIdentity()) {
1950
for (Eigen::Index i = 0; i < numPoints; i++) {
1951
data(i, col0) = normals[i].x;
1952
data(i, col1) = normals[i].y;
1953
data(i, col2) = normals[i].z;
1958
for (Eigen::Index i = 0; i < numPoints; i++) {
1959
tmp = Base::convertTo<Base::Vector3d>(normals[i]);
1960
rot.multVec(tmp, tmp);
1961
data(i, col0) = static_cast<float>(tmp.x);
1962
data(i, col1) = static_cast<float>(tmp.y);
1963
data(i, col2) = static_cast<float>(tmp.z);
1970
Eigen::Index col0 = col;
1971
Eigen::Index col1 = col + 1;
1972
Eigen::Index col2 = col + 2;
1973
Eigen::Index col3 = col + 3;
1974
for (Eigen::Index i = 0; i < numPoints; i++) {
1975
App::Color c = colors[i];
1976
data(i, col0) = (c.r * 255.0F + 0.5F);
1977
data(i, col1) = (c.g * 255.0F + 0.5F);
1978
data(i, col2) = (c.b * 255.0F + 0.5F);
1979
data(i, col3) = (c.a * 255.0F + 0.5F);
1985
for (Eigen::Index i = 0; i < numPoints; i++) {
1986
data(i, col) = intensity[i];
1991
Base::ofstream out(Base::FileInfo(filename), std::ios::out);
1992
out << "ply" << std::endl
1993
<< "format ascii 1.0" << std::endl
1994
<< "comment FreeCAD generated" << std::endl;
1995
out << "element vertex " << numValid << std::endl;
1998
for (const auto& prop : properties) {
1999
out << "property " << prop << std::endl;
2001
out << "end_header" << std::endl;
2003
for (Eigen::Index r = 0; r < numPoints; r++) {
2004
if (boost::math::isnan(data(r, 0))) {
2007
if (boost::math::isnan(data(r, 1))) {
2010
if (boost::math::isnan(data(r, 2))) {
2013
for (Eigen::Index c = 0; c < col; c++) {
2014
float value = data(r, c);
2015
out << converters[c]->toString(value) << " ";
2023
PcdWriter::PcdWriter(const PointKernel& p)
2027
void PcdWriter::write(const std::string& filename)
2029
std::list<std::string> fields;
2030
fields.emplace_back("x");
2031
fields.emplace_back("y");
2032
fields.emplace_back("z");
2034
std::list<std::string> types;
2035
types.emplace_back("F");
2036
types.emplace_back("F");
2037
types.emplace_back("F");
2039
ConverterPtr convert_float(new ConverterT<float>);
2040
ConverterPtr convert_uint(new ConverterT<uint32_t>);
2042
std::vector<ConverterPtr> converters;
2043
converters.push_back(convert_float);
2044
converters.push_back(convert_float);
2045
converters.push_back(convert_float);
2047
bool hasIntensity = (intensity.size() == points.size());
2048
bool hasColors = (colors.size() == points.size());
2049
bool hasNormals = (normals.size() == points.size());
2052
fields.emplace_back("normal_x");
2053
fields.emplace_back("normal_y");
2054
fields.emplace_back("normal_z");
2055
types.emplace_back("F");
2056
types.emplace_back("F");
2057
types.emplace_back("F");
2058
converters.push_back(convert_float);
2059
converters.push_back(convert_float);
2060
converters.push_back(convert_float);
2064
fields.emplace_back("rgba");
2065
types.emplace_back("U");
2066
converters.push_back(convert_uint);
2070
fields.emplace_back("intensity");
2071
types.emplace_back("F");
2072
converters.push_back(convert_float);
2075
Eigen::Index numPoints = Eigen::Index(points.size());
2076
const std::vector<Base::Vector3f>& pts = points.getBasicPoints();
2078
Eigen::MatrixXd data(numPoints, fields.size());
2080
if (placement.isIdentity()) {
2081
for (Eigen::Index i = 0; i < numPoints; i++) {
2082
data(i, 0) = pts[i].x;
2083
data(i, 1) = pts[i].y;
2084
data(i, 2) = pts[i].z;
2089
for (Eigen::Index i = 0; i < numPoints; i++) {
2090
tmp = Base::convertTo<Base::Vector3d>(pts[i]);
2091
placement.multVec(tmp, tmp);
2092
data(i, 0) = static_cast<float>(tmp.x);
2093
data(i, 1) = static_cast<float>(tmp.y);
2094
data(i, 2) = static_cast<float>(tmp.z);
2098
Eigen::Index col = 3;
2100
Eigen::Index col0 = col;
2101
Eigen::Index col1 = col + 1;
2102
Eigen::Index col2 = col + 2;
2103
Base::Rotation rot = placement.getRotation();
2104
if (rot.isIdentity()) {
2105
for (Eigen::Index i = 0; i < numPoints; i++) {
2106
data(i, col0) = normals[i].x;
2107
data(i, col1) = normals[i].y;
2108
data(i, col2) = normals[i].z;
2113
for (Eigen::Index i = 0; i < numPoints; i++) {
2114
tmp = Base::convertTo<Base::Vector3d>(normals[i]);
2115
rot.multVec(tmp, tmp);
2116
data(i, col0) = static_cast<float>(tmp.x);
2117
data(i, col1) = static_cast<float>(tmp.y);
2118
data(i, col2) = static_cast<float>(tmp.z);
2125
for (Eigen::Index i = 0; i < numPoints; i++) {
2127
data(i, col) = colors[i].getPackedARGB();
2133
for (Eigen::Index i = 0; i < numPoints; i++) {
2134
data(i, col) = intensity[i];
2139
std::size_t numFields = fields.size();
2140
Base::ofstream out(Base::FileInfo(filename), std::ios::out);
2141
out << "# .PCD v0.7 - Point Cloud Data file format" << std::endl << "VERSION 0.7" << std::endl;
2145
for (const auto& field : fields) {
2146
out << " " << field;
2152
for (std::size_t i = 0; i < numFields; i++) {
2159
for (const auto& type : types) {
2166
for (std::size_t i = 0; i < numFields; i++) {
2171
out << "WIDTH " << width << std::endl;
2172
out << "HEIGHT " << height << std::endl;
2174
Base::Placement plm;
2175
Base::Vector3d p = plm.getPosition();
2176
Base::Rotation o = plm.getRotation();
2181
o.getValue(x, y, z, w);
2182
out << "VIEWPOINT " << p.x << " " << p.y << " " << p.z << " " << w << " " << x << " " << y
2183
<< " " << z << std::endl;
2185
out << "POINTS " << numPoints << std::endl << "DATA ascii" << std::endl;
2187
for (Eigen::Index r = 0; r < numPoints; r++) {
2188
for (Eigen::Index c = 0; c < col; c++) {
2189
double value = data(r, c);
2190
if (boost::math::isnan(value)) {
2194
out << converters[c]->toString(value) << " ";