pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/common/SVGLoader_TEST.cc

372 lines
11 KiB
C++

/*
* Copyright (C) 2015 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <gtest/gtest.h>
#include "test_config.h"
#include "gazebo/common/SVGLoader.hh"
#include "test/util.hh"
using namespace gazebo;
class SVGLoader : public gazebo::testing::AutoLogFixture { };
// tolerance
// minimum distance between 2 distinct points
double tol = 0.05;
/////////////////////////////////////////////////
TEST_F(SVGLoader, LoadPaths)
{
common::SVGLoader loader(10);
std::vector<common::SVGPath> paths;
// bad path
bool success;
std::string bad = "/not/a/file.svg";
success = loader.Parse(bad, paths);
EXPECT_FALSE(success);
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/loader.svg";
loader.Parse(filePath, paths);
// useful to see the points on screen
// loader.DumpPaths(paths, std::cout);
// or in a file
std::string foutput = "";
if (!foutput.empty())
{
std::ofstream out(foutput.c_str() );
loader.DumpPaths(paths, out);
out.close();
}
// the test file has 3 paths inside
EXPECT_EQ(3u, paths.size());
common::SVGPath &a = paths[0];
EXPECT_EQ("letterA", a.id);
// the letter A has 2 subpaths:
EXPECT_EQ(2u, a.subpaths.size());
// The hole of A
// 4 commands
EXPECT_EQ(4u, a.subpaths[0].size());
// 4 points
EXPECT_EQ(4u, a.polylines[0].size());
// The A contour has 9
EXPECT_EQ(9u, a.polylines[1].size());
// see what's going on
loader.DumpPaths(paths, std::cout);
// the second path
common::SVGPath &p2 = paths[1];
EXPECT_EQ(1u, p2.subpaths.size());
EXPECT_EQ("path2984", p2.id);
// 8 commands
EXPECT_EQ(8u, p2.subpaths[0].size());
// since it has splines, there are more
// points than commands
EXPECT_EQ(68u, p2.polylines[0].size());
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, LoadArcs)
{
// check for arc command support
// this test loads a file with 2 superimposed 180 degree arc:
// * drawn from right to left
// * with a round top (looks like an igloo, not a bowl)
// therefore, y DECREASES (y is down in svg)
//
// This test ensures that both path coincide (and not form a circle)
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/arc_test.svg";
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
// the test file has 2 paths inside
EXPECT_EQ(2u, paths.size());
// each path has the same number of points
EXPECT_EQ(1u, paths[0].polylines.size());
EXPECT_EQ(1u, paths[1].polylines.size());
auto &polyline1 = paths[0].polylines[0];
auto &polyline2 = paths[1].polylines[0];
for (auto i = 0u; i != polyline1.size(); ++i)
{
// extract points
auto p1 = polyline1[i];
auto p2 = polyline2[i];
EXPECT_NEAR(p1.X(), p2.X(), 0.25);
EXPECT_NEAR(p1.Y(), p2.Y(), 0.25);
}
std::ofstream out("arc_test.html");
loader.DumpPaths(paths, out);
out.close();
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, Capsule)
{
// check for arc command support
// this test loads a file with 2 superimposed 180 degree arc:
// * drawn from right to left
// * with a round top (looks like an igloo, not a bowl)
// therefore, y DECREASES (y is down in svg)
//
// This test ensures that both path coincide (and not form a circle)
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/capsule.svg";
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
// the test file has 2 paths inside
std::ofstream out("capsule.html");
loader.DumpPaths(paths, out);
out.close();
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, ghost_edges)
{
// check for invalid edges in svg
// this test loads a file with a circle made of 2 arcs:
//
// The resulting polyline should not have duplicate points
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/arc_circle.svg";
bool success = loader.Parse(filePath, paths);
// save for inspection
std::ofstream out("arc_circle.html");
loader.DumpPaths(paths, out);
out.close();
EXPECT_EQ(true, success);
// the test file has 2 paths inside
EXPECT_EQ(1u, paths.size());
EXPECT_EQ(1u, paths[0].polylines.size());
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, ClosedLoops)
{
// this tests the PathsToClosedPolylines function
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/chassis.svg";
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
// save for inspection
std::ofstream out("chassis.html");
loader.DumpPaths(paths, out);
out.close();
std::vector< std::vector<ignition::math::Vector2d> > closedPolys;
std::vector< std::vector<ignition::math::Vector2d> > openPolys;
loader.PathsToClosedPolylines(paths, tol, closedPolys, openPolys);
EXPECT_EQ(0u, openPolys.size());
EXPECT_EQ(23u, closedPolys.size());
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, Transforms)
{
// this tests the scale, matrix and rotation transforms
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/transform.svg";
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
// save for inspection
std::ofstream out("transform.html");
loader.DumpPaths(paths, out);
out.close();
std::vector< std::vector<ignition::math::Vector2d> > closedPolys;
std::vector< std::vector<ignition::math::Vector2d> > openPolys;
loader.PathsToClosedPolylines(paths, tol, closedPolys, openPolys);
EXPECT_EQ(0u, openPolys.size());
EXPECT_EQ(2u, closedPolys.size());
// without transform, the first segment of the first polyline is
// about 132 units along y
auto p0 = closedPolys[0][0];
auto p1 = closedPolys[0][1];
double dy = fabs(p0.Y() - p1.Y());
EXPECT_LE(dy, 40.0);
// without transform, the first segment of the second poly is horizontal
// (y is constant, dy is 0)
dy = fabs(closedPolys[1][0].Y() - closedPolys[1][1].Y() );
EXPECT_GT(dy, 150.0);
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, Transforms2)
{
// this tests the skewY and skewX transforms
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/transform2.svg";
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
// save for inspection
std::ofstream out("transform2.html");
loader.DumpPaths(paths, out);
out.close();
std::vector< std::vector<ignition::math::Vector2d> > closedPolys;
std::vector< std::vector<ignition::math::Vector2d> > openPolys;
loader.PathsToClosedPolylines(paths, tol, closedPolys, openPolys);
EXPECT_EQ(0u, openPolys.size());
EXPECT_EQ(3u, closedPolys.size());
EXPECT_EQ("original", paths[0].id);
double dxOriginal = fabs(closedPolys[0][0].X() - closedPolys[0][1].X() );
double dyOriginal = fabs(closedPolys[0][0].Y() - closedPolys[0][1].Y() );
gzmsg << dxOriginal << " X original 0-1\n";
gzmsg << dyOriginal << " Y original 0-1\n";
// the sgment is vertical (dx = 0)
EXPECT_DOUBLE_EQ(dxOriginal, 0);
EXPECT_EQ("skewx", paths[1].id);
double dxSkewX = fabs(closedPolys[1][0].X() - closedPolys[1][1].X() );
double dySkewX = fabs(closedPolys[1][0].Y() - closedPolys[1][1].Y() );
gzmsg << dxSkewX << " X skewX 0-1\n";
gzmsg << dySkewX << " Y skewX 0-1\n";
// the segment is 45 degree, hence dx = dy
EXPECT_DOUBLE_EQ(dxSkewX, dySkewX);
EXPECT_EQ("skewy", paths[2].id);
double dxSkewY = fabs(closedPolys[2][0].X() - closedPolys[2][1].X() );
double dySkewY = fabs(closedPolys[2][0].Y() - closedPolys[2][1].Y() );
gzmsg << dxSkewY << " X skewY 0-1\n";
gzmsg << dySkewY << " Y skewY 0-1\n";
// the segment is vertical (dx = 0)
EXPECT_DOUBLE_EQ(dxOriginal, dxSkewY);
// segment is skewed 30 degrees
double dxSkewYb = fabs(closedPolys[2][5].X() - closedPolys[2][4].X() );
double dySkewYb = fabs(closedPolys[2][5].Y() - closedPolys[2][4].Y() );
gzmsg << dxSkewYb << " X skewY b\n";
gzmsg << dySkewYb << " Y skewY b\n";
EXPECT_GT(dxSkewYb, 131.0);
EXPECT_GT(dySkewYb, 35.0);
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, Transforms3)
{
// this tests the skewY and skewX transforms
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/transform3.svg";
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
EXPECT_EQ(3u, paths.size());
EXPECT_EQ("outer_path", paths[0].id);
EXPECT_EQ("path_no_tx", paths[1].id);
EXPECT_EQ("path_tx", paths[2].id);
gzerr << paths[0].id << " tx: " << paths[0].transform << std::endl;
gzerr << paths[1].id << " tx: " << paths[1].transform << std::endl;
gzerr << paths[2].id << " tx: " << paths[2].transform << std::endl;
// save for inspection
std::ofstream out("transform3.html");
loader.DumpPaths(paths, out);
out.close();
std::vector< std::vector<ignition::math::Vector2d> > closedPolys;
std::vector< std::vector<ignition::math::Vector2d> > openPolys;
loader.PathsToClosedPolylines(paths, tol, closedPolys, openPolys);
EXPECT_EQ(0u, openPolys.size());
EXPECT_EQ(3u, closedPolys.size());
}
/////////////////////////////////////////////////
TEST_F(SVGLoader, MultipleFiles)
{
// this test can load multiple svg files and
// save the html for inspection
std::vector<std::string> files;
files.push_back("issue_1489_5.svg");
for (auto file : files)
{
// this tests the skewY and skewX transforms
common::SVGLoader loader(3);
std::vector<common::SVGPath> paths;
std::string filePath = std::string(PROJECT_SOURCE_PATH);
filePath += "/test/data/svg/";
filePath += file;
bool success = loader.Parse(filePath, paths);
EXPECT_EQ(true, success);
// save for inspection
std::ofstream out(file + ".html");
loader.DumpPaths(paths, out);
out.close();
}
}
/////////////////////////////////////////////////
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}