Skip to content

Commit

Permalink
Move file lookup code out of parser_common
Browse files Browse the repository at this point in the history
This is to avoid adding extra dependency on RBT.
  • Loading branch information
sammy-tri committed May 23, 2018
1 parent 1add744 commit 0376cdf
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 161 deletions.
33 changes: 25 additions & 8 deletions multibody/parsers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,49 @@ package(default_visibility = ["//visibility:public"])
drake_cc_package_library(
name = "parsers",
deps = [
":everything",
":find_files",
":parsing",
],
)

drake_cc_library(
name = "everything",
name = "parsing",
srcs = [
"model_instance_id_table.cc",
"package_map.cc",
"parser_common.cc",
"sdf_parser.cc",
"urdf_parser.cc",
"xml_util.cc",
],
hdrs = [
"model_instance_id_table.h",
"package_map.h",
"parser_common.h",
"sdf_parser.h",
"urdf_parser.h",
"xml_util.h",
],
visibility = ["//visibility:private"],
deps = [
":find_files",
"//multibody:rigid_body_tree",
"//multibody/rigid_body_plant:compliant_material",
"@tinydir",
"@tinyxml2",
],
)

drake_cc_library(
name = "find_files",
srcs = [
"package_map.cc",
"parser_path_utils.cc",
],
hdrs = [
"package_map.h",
"parser_path_utils.h",
],
deps = [
"//common",
"@spruce",
"@tinydir",
"@tinyxml2",
Expand All @@ -58,16 +75,16 @@ drake_cc_googletest(
":test_models",
],
deps = [
":parsers",
":find_files",
"//common:find_resource",
],
)

drake_cc_googletest(
name = "parser_common_test",
srcs = ["test/parser_common_test/parser_common_test.cc"],
name = "parser_path_utils_test",
srcs = ["test/parser_path_utils_test.cc"],
deps = [
":parsers",
":find_files",
],
)

Expand Down
115 changes: 0 additions & 115 deletions multibody/parsers/parser_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
#include <string>
#include <utility>

#include <spruce.hh>

#include "drake/common/drake_assert.h"
#include "drake/common/text_logging.h"
#include "drake/multibody/joints/drake_joint.h"
#include "drake/multibody/joints/fixed_joint.h"
Expand All @@ -32,118 +29,6 @@ using tinyxml2::XMLElement;
const char* const FloatingJointConstants::kFloatingJointName = "base";
const char* const FloatingJointConstants::kWeldJointName = "weld";

string GetFullPath(const string& file_name) {
string result = file_name;
if (result.empty()) {
throw std::runtime_error("drake::parsers::GetFullPath: ERROR: file_name is "
"empty.");
}

const string prefix = "/";
if (result.substr(0, prefix.size()) == prefix) {
// The specified file is already an absolute path. The following code
// verifies that the file exists.
spruce::path path(file_name);
if (!path.isFile()) {
throw std::runtime_error("drake::parsers::GetFullPath: ERROR: "
"file_name \"" + file_name + "\" is not a file.");
}
} else {
// The specified file is a relative path. The following code obtains the
// full path and verifies that the file exists.
spruce::path path = spruce::dir::getcwd();
path.append(file_name);
if (path.isFile()) {
result = path.getStr();
} else {
throw std::runtime_error("drake::parsers::GetFullPath: ERROR: "
"file_name \"" + file_name + "\" is not a file or does not exist.");
}
}
return result;
}

namespace {
// Searches for key p package in package_map. If the key exists, this saves the
// associated value in the string pointed to by package_path and then returns
// true. It returns false otherwise.
bool GetPackagePath(const string& package, const PackageMap& package_map,
string* package_path) {
if (package_map.Contains(package)) {
*package_path = package_map.GetPath(package);
return true;
} else {
drake::log()->warn("Couldn't find package '{}' in the supplied package"
"path.", package);
return false;
}
}
} // anonymous namespace

// The unit test that most directly covers this method is:
// drake/multibody/parsers/test/urdf_parser_test/urdf_parser_test.cc.
string ResolveFilename(const string& filename, const PackageMap& package_map,
const string& root_dir) {
spruce::path mesh_filename_spruce;
spruce::path raw_filename_spruce(filename);

vector<string> split_filename = raw_filename_spruce.split();

if (split_filename.front() == "package:") {
// A correctly formatted filename is:
//
// package://package_name/bar/baz/model.xyz
//
// Thus, index 0 contains "package", index 1 contains "", and index 2
// contains the package name. Furthermore, since the model file must follow
// the package name, there must be at least 4 tokens.
const int kMinNumTokens = 4;
const int kPackageNameIndex = 2;
DRAKE_DEMAND(split_filename.size() >= kMinNumTokens);

string package_path_string;
if (GetPackagePath(split_filename.at(kPackageNameIndex), package_map,
&package_path_string)) {
mesh_filename_spruce = spruce::path(package_path_string);

auto split_raw = raw_filename_spruce.split();
// The following loop starts at index 3 to skip the "package", "", and
// [package name] tokens as described above.
for (int i = kPackageNameIndex + 1;
i < static_cast<int>(split_raw.size()); ++i) {
mesh_filename_spruce.append(split_raw.at(i));
}
} else {
drake::log()->warn("Mesh '{}' could not be resolved and will be ignored "
"by Drake. If you don't want it to be ignored, please "
"include it in the package map.", filename);
return string();
}
} else {
string normalized_root_dir = spruce::path(root_dir).getStr();

// If root_dir is a relative path, convert it to an absolute path.
bool dir_is_relative =
!(normalized_root_dir.size() >= 1 && normalized_root_dir[0] == '/');
if (dir_is_relative) {
mesh_filename_spruce = spruce::dir::getcwd();
mesh_filename_spruce.append(normalized_root_dir);
} else {
mesh_filename_spruce = spruce::path(normalized_root_dir);
}

mesh_filename_spruce.append(filename);
}
if (!mesh_filename_spruce.exists()) {
drake::log()->warn("File '{}' could not be found.",
mesh_filename_spruce.getStr());
drake::log()->warn("Mesh '{}' could not be resolved and will be ignored by "
"Drake.", filename);
return string();
}
return mesh_filename_spruce.getStr();
}

int AddFloatingJoint(
const FloatingBaseType floating_base_type,
const vector<int>& body_indices,
Expand Down
32 changes: 0 additions & 32 deletions multibody/parsers/parser_common.h
Original file line number Diff line number Diff line change
@@ -1,51 +1,19 @@
#pragma once

#include <memory>
#include <string>
#include <vector>

#include <tinyxml2.h>

#include "drake/multibody/joints/floating_base_types.h"
#include "drake/multibody/parsers/model_instance_id_table.h"
#include "drake/multibody/parsers/package_map.h"
#include "drake/multibody/rigid_body_frame.h"
#include "drake/multibody/rigid_body_plant/compliant_material.h"
#include "drake/multibody/rigid_body_tree.h"

namespace drake {
namespace parsers {

// Obtains the full path of @file_name. If @p file_name is already a full path
// (i.e., it starts with a "/"), this method returns it unmodified after
// verifying that the file exists. If @p file_name is a relative path, this
// method converts it into an absolute path based on the current working
// directory, and then, if the file exists, returns the full path. In either
// scenario, if the file does not exist, this method will throw a
// std::runtime_error exception.
std::string GetFullPath(const std::string& file_name);

/// Resolves the fully-qualified name of a file. If @p filename starts with
/// "package:", the ROS packages specified in @p package_map are searched.
/// Otherwise, @p filename is appended to the end of @p root_dir and checked
/// for existence. If the file does not exist or is not found, a warning is
/// printed to `std::cerr` and an empty string is returned.
///
/// @param[in] filename The name of the file to find.
///
/// @param[in] package_map A map where the keys are ROS package names and the
/// values are the paths to the packages. This is only used if @p filename
/// starts with "package:".
///
/// @param[in] root_dir The root directory to look in. This is only used when
/// @p filename does not start with "package:".
///
/// @return The file's fully-qualified name or an empty string if the file is
/// not found or does not exist.
std::string ResolveFilename(const std::string& filename,
const PackageMap& package_map,
const std::string& root_dir);

/// Defines constants used by AddFloatingJoint().
struct FloatingJointConstants {
static const char* const kFloatingJointName;
Expand Down
132 changes: 132 additions & 0 deletions multibody/parsers/parser_path_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "drake/multibody/parsers/parser_path_utils.h"

#include <string>
#include <vector>

#include <spruce.hh>

#include "drake/common/drake_assert.h"
#include "drake/common/text_logging.h"

using std::string;

namespace drake {
namespace parsers {
namespace {
bool IsAbsolutePath(const string& filename) {
const string prefix = "/";
return filename.substr(0, prefix.size()) == prefix;
}
} // namespace

string GetFullPath(const string& file_name) {
string result = file_name;
if (result.empty()) {
throw std::runtime_error("drake::parsers::GetFullPath: ERROR: file_name is "
"empty.");
}

if (IsAbsolutePath(result)) {
// The specified file is already an absolute path. The following code
// verifies that the file exists.
spruce::path path(file_name);
if (!path.isFile()) {
throw std::runtime_error("drake::parsers::GetFullPath: ERROR: "
"file_name \"" + file_name + "\" is not a file.");
}
} else {
// The specified file is a relative path. The following code obtains the
// full path and verifies that the file exists.
spruce::path path = spruce::dir::getcwd();
path.append(file_name);
if (path.isFile()) {
result = path.getStr();
} else {
throw std::runtime_error("drake::parsers::GetFullPath: ERROR: "
"file_name \"" + file_name + "\" is not a file or does not exist.");
}
}
return result;
}

namespace {
// Searches for key package in package_map. If the key exists, this saves the
// associated value in the string pointed to by package_path and then returns
// true. It returns false otherwise.
bool GetPackagePath(const string& package, const PackageMap& package_map,
string* package_path) {
if (package_map.Contains(package)) {
*package_path = package_map.GetPath(package);
return true;
} else {
drake::log()->warn("Couldn't find package '{}' in the supplied package"
"path.", package);
return false;
}
}
} // namespace

// The unit test that most directly covers this method is:
// drake/multibody/parsers/test/urdf_parser_test/urdf_parser_test.cc.
string ResolveFilename(const string& filename, const PackageMap& package_map,
const string& root_dir) {
spruce::path full_filename_spruce;
spruce::path raw_filename_spruce(filename);
const std::vector<string> split_filename = raw_filename_spruce.split();

if (IsAbsolutePath(filename)) {
if (!raw_filename_spruce.exists()) {
drake::log()->warn("File {} could not be found.", filename);
return string();
}
return filename;
} else if (split_filename.front() == "package:") {
// A correctly formatted filename is:
//
// package://package_name/bar/baz/model.xyz
//
// Thus, index 0 contains "package", index 1 contains "", and index 2
// contains the package name. Furthermore, since the model file must follow
// the package name, there must be at least 4 tokens.
const int kMinNumTokens = 4;
const int kPackageNameIndex = 2;
DRAKE_DEMAND(split_filename.size() >= kMinNumTokens);

string package_path_string;
if (GetPackagePath(split_filename.at(kPackageNameIndex), package_map,
&package_path_string)) {
full_filename_spruce = spruce::path(package_path_string);

// The following loop starts at index 3 to skip the "package", "", and
// [package name] tokens as described above.
for (int i = kPackageNameIndex + 1;
i < static_cast<int>(split_filename.size()); ++i) {
full_filename_spruce.append(split_filename.at(i));
}
} else {
return string();
}
} else {
const string normalized_root_dir = spruce::path(root_dir).getStr();

// If root_dir is a relative path, convert it to an absolute path.
if (!IsAbsolutePath(normalized_root_dir)) {
full_filename_spruce = spruce::dir::getcwd();
full_filename_spruce.append(normalized_root_dir);
} else {
full_filename_spruce = spruce::path(normalized_root_dir);
}

full_filename_spruce.append(filename);
}

if (!full_filename_spruce.exists()) {
drake::log()->warn("File {} resolved to {} and could not be found.",
filename, full_filename_spruce.getStr());
return string();
}
return full_filename_spruce.getStr();
}

} // namespace parsers
} // namespace drake
Loading

0 comments on commit 0376cdf

Please sign in to comment.