diff --git a/io/src/obj_io.cpp b/io/src/obj_io.cpp index 3586f6890fe..934c6bb953b 100644 --- a/io/src/obj_io.cpp +++ b/io/src/obj_io.cpp @@ -374,7 +374,6 @@ pcl::OBJReader::readHeader (const std::string &file_name, pcl::PCLPointCloud2 &c // bool material_found = false; std::vector material_files; std::size_t nr_point = 0; - std::vector st; try { @@ -385,40 +384,42 @@ pcl::OBJReader::readHeader (const std::string &file_name, pcl::PCLPointCloud2 &c if (line == "") continue; - // Tokenize the line - std::stringstream sstream (line); - sstream.imbue (std::locale::classic ()); - line = sstream.str (); + // Trim the line boost::trim (line); - boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on); + // Ignore comments - if (st.at (0) == "#") + if (line[0] == '#') continue; - // Vertex - if (st.at (0) == "v") + // Vertex, vertex texture or vertex normal + if (line[0] == 'v') { - ++nr_point; - continue; - } + // Vertex (v) + if ((line[1] == ' ')) { + ++nr_point; + continue; + } - // Vertex texture - if ((st.at (0) == "vt") && !vertex_texture_found) - { - vertex_texture_found = true; - continue; - } + // Vertex texture (vt) + else if ((line[1] == 't') && !vertex_texture_found) + { + vertex_texture_found = true; + continue; + } - // Vertex normal - if ((st.at (0) == "vn") && !vertex_normal_found) - { - vertex_normal_found = true; - continue; + // Vertex normal (vn) + else if ((line[1] == 'n') && !vertex_normal_found) + { + vertex_normal_found = true; + continue; + } } // Material library, skip for now! - if (st.at (0) == "mtllib") + if (line.substr (0, 6) == "mtllib") { + std::vector st; + boost::split(st, line, boost::is_any_of("\t\r "), boost::token_compress_on); material_files.push_back (st.at (1)); continue; } @@ -588,6 +589,13 @@ pcl::OBJReader::read (const std::string &file_name, pcl::PCLPointCloud2 &cloud, // Vertex normal if (st[0] == "vn") { + if (normal_idx >= cloud.width) + { + if (normal_idx == cloud.width) + PCL_WARN ("[pcl:OBJReader] Too many vertex normals (expected %d), skipping remaining normals.\n", cloud.width, normal_idx + 1); + ++normal_idx; + continue; + } try { for (int i = 1, f = normal_x_field; i < 4; ++i, ++f) diff --git a/test/io/test_io.cpp b/test/io/test_io.cpp index 22ab1b420d0..2922cdb9021 100644 --- a/test/io/test_io.cpp +++ b/test/io/test_io.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -156,6 +157,8 @@ TEST (PCL, ComplexPCDFileASCII) EXPECT_EQ (val[30], 0); EXPECT_EQ (val[31], 0); EXPECT_EQ (val[32], 0); + + remove ("complex_ascii.pcd"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -255,6 +258,8 @@ TEST (PCL, AllTypesPCDFile) EXPECT_FLOAT_EQ (float (b8), -250.05f); memcpy (&b8, &blob.data[blob.fields[7].offset + sizeof (double)], sizeof (double)); EXPECT_FLOAT_EQ (float (b8), -251.05f); + + remove ("all_types.pcd"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -652,6 +657,10 @@ TEST (PCL, IO) EXPECT_FLOAT_EQ (cloud.points[0].y, first.y); // test for fromPCLPointCloud2 () EXPECT_FLOAT_EQ (cloud.points[0].z, first.z); // test for fromPCLPointCloud2 () EXPECT_FLOAT_EQ (cloud.points[0].intensity, first.intensity); // test for fromPCLPointCloud2 () + + remove ("test_pcl_io_ascii.pcd"); + remove ("test_pcl_io_binary.pcd"); + remove ("test_pcl_io.pcd"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -720,6 +729,8 @@ TEST (PCL, PCDReaderWriter) EXPECT_FLOAT_EQ (cloud.points[nr_p - 1].y, last.y); // test for fromPCLPointCloud2 () EXPECT_FLOAT_EQ (cloud.points[nr_p - 1].z, last.z); // test for fromPCLPointCloud2 () EXPECT_FLOAT_EQ (cloud.points[nr_p - 1].intensity, last.intensity); // test for fromPCLPointCloud2 () + + remove ("test_pcl_io.pcd"); } TEST (PCL, PCDReaderWriterASCIIColorPrecision) @@ -763,10 +774,13 @@ TEST (PCL, PCDReaderWriterASCIIColorPrecision) EXPECT_EQ (cloud[i].g, cloud_ascii[i].g); EXPECT_EQ (cloud[i].b, cloud_ascii[i].b); } + + remove ("temp_binary_color.pcd"); + remove ("temp_ascii_color.pcd"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TEST (PCL, ASCIIReader) +TEST (PCL, ASCIIRead) { PointCloud cloud, rcloud; @@ -806,6 +820,98 @@ TEST (PCL, ASCIIReader) EXPECT_FLOAT_EQ(cloud.points[i].intensity, rcloud.points[i].intensity); } + remove ("test_pcd.txt"); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +TEST(PCL, OBJRead) +{ + std::ofstream fs; + fs.open ("test_obj.obj"); + fs << "# Blender v2.79 (sub 4) OBJ File: ''\n" + "mtllib test_obj.mtl\n" + "o Cube_Cube.001\n" + "v -1.000000 -1.000000 1.000000\n" + "v -1.000000 1.000000 1.000000\n" + "v -1.000000 -1.000000 -1.000000\n" + "v -1.000000 1.000000 -1.000000\n" + "v 1.000000 -1.000000 1.000000\n" + "v 1.000000 1.000000 1.000000\n" + "v 1.000000 -1.000000 -1.000000\n" + "v 1.000000 1.000000 -1.000000\n" + "vn -1.0000 0.0000 0.0000\n" + "vn 0.0000 0.0000 -1.0000\n" + "vn 1.0000 0.0000 0.0000\n" + "vn 0.0000 0.0000 1.0000\n" + "vn 0.0000 -1.0000 0.0000\n" + "vn 0.0000 1.0000 0.0000\n" + "# Redundant vertex normal to test error handling\n" + "vn 0.0000 0.0000 0.0000\n" + "usemtl None\n" + "s off\n" + "f 1//1 2//1 4//1 3//1\n" + "f 3//2 4//2 8//2 7//2\n" + "f 7//3 8//3 6//3 5//3\n" + "f 5//4 6//4 2//4 1//4\n" + "f 3//5 7//5 5//5 1//5\n" + "f 8//6 4//6 2//6 6//6\n"; + + fs.close (); + fs.open ("test_obj.mtl"); + fs << "# Blender MTL File: 'None'\n" + "# Material Count: 1\n" + "newmtl None\n" + "Ns 0\n" + "Ka 0.000000 0.000000 0.000000\n" + "Kd 0.8 0.8 0.8\n" + "Ks 0.8 0.8 0.8\n" + "d 1\n" + "illum 2\n"; + + fs.close (); + + pcl::PCLPointCloud2 blob; + pcl::OBJReader objreader = pcl::OBJReader(); + int res = objreader.read ("test_obj.obj", blob); + EXPECT_NE (int (res), -1); + EXPECT_EQ (blob.width, 8); + EXPECT_EQ (blob.height, 1); + EXPECT_EQ (blob.is_dense, true); + EXPECT_EQ (blob.data.size (), 8 * 6 * 4); // 8 verts, 6 values per vertex (vx,vy,vz,vnx,vny,vnz), 4 byte per value + + // Check fields + EXPECT_EQ (blob.fields[0].name, "x"); + EXPECT_EQ (blob.fields[0].offset, 0); + EXPECT_EQ (blob.fields[0].count, 1); + EXPECT_EQ (blob.fields[0].datatype, pcl::PCLPointField::FLOAT32); + + EXPECT_EQ (blob.fields[1].name, "y"); + EXPECT_EQ (blob.fields[1].offset, 4 * 1); + EXPECT_EQ (blob.fields[1].count, 1); + EXPECT_EQ (blob.fields[1].datatype, pcl::PCLPointField::FLOAT32); + + EXPECT_EQ (blob.fields[2].name, "z"); + EXPECT_EQ (blob.fields[2].offset, 4 * 2); + EXPECT_EQ (blob.fields[2].count, 1); + EXPECT_EQ (blob.fields[2].datatype, pcl::PCLPointField::FLOAT32); + + EXPECT_EQ (blob.fields[3].name, "normal_x"); + EXPECT_EQ (blob.fields[3].offset, 4 * 3); + EXPECT_EQ (blob.fields[3].count, 1); + EXPECT_EQ (blob.fields[3].datatype, pcl::PCLPointField::FLOAT32); + + EXPECT_EQ (blob.fields[4].name, "normal_y"); + EXPECT_EQ (blob.fields[4].offset, 4 * 4); + EXPECT_EQ (blob.fields[4].count, 1); + EXPECT_EQ (blob.fields[4].datatype, pcl::PCLPointField::FLOAT32); + + EXPECT_EQ (blob.fields[5].name, "normal_z"); + EXPECT_EQ (blob.fields[5].offset, 4 * 5); + EXPECT_EQ (blob.fields[5].count, 1); + EXPECT_EQ (blob.fields[5].datatype, pcl::PCLPointField::FLOAT32); + + remove ("test_obj.obj"); + remove ("test_obj.mtl"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -858,6 +964,8 @@ TEST (PCL, ExtendedIO) ASSERT_EQ (cloud.points[0].histogram[i], i); ASSERT_EQ (cloud.points[1].histogram[i], 33-i); } + + remove ("v.pcd"); } @@ -1057,6 +1165,8 @@ TEST (PCL, LZFExtended) EXPECT_EQ (cloud2.points[i].normal_z, cloud.points[i].normal_z); EXPECT_EQ (cloud2.points[i].rgb, cloud.points[i].rgb); } + + remove ("test_pcl_io_compressed.pcd"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1202,6 +1312,8 @@ TEST (PCL, Locale) catch (const std::exception&) { } + + remove ("test_pcl_io_ascii.pcd"); #endif }