Refactor numerical parsing in XML.
PiperOrigin-RevId: 653979240 Change-Id: I4d39f4041b88396193eb35f0cc393141d64f6fc0
This commit is contained in:
committed by
Copybara-Service
parent
e92af73cbf
commit
8a8a44a4db
@@ -1317,17 +1317,17 @@ void mjXReader::OneFlex(XMLElement* elem, mjsFlex* pflex) {
|
||||
if (ReadAttrTxt(elem, "body", text, true)) {
|
||||
mjs_setStringVec(pflex->vertbody, text.c_str());
|
||||
}
|
||||
if (ReadAttrTxt(elem, "vertex", text)) {
|
||||
std::vector<double> vert = String2Vector<double>(text);
|
||||
mjs_setDouble(pflex->vert, vert.data(), vert.size());
|
||||
auto vert = ReadAttrVec<double>(elem, "vertex");
|
||||
if (vert.has_value()) {
|
||||
mjs_setDouble(pflex->vert, vert->data(), vert->size());
|
||||
}
|
||||
if (ReadAttrTxt(elem, "element", text, true)) {
|
||||
std::vector<int> elem = String2Vector<int>(text);
|
||||
mjs_setInt(pflex->elem, elem.data(), elem.size());
|
||||
auto element = ReadAttrVec<int>(elem, "element", true);
|
||||
if (element.has_value()) {
|
||||
mjs_setInt(pflex->elem, element->data(), element->size());
|
||||
}
|
||||
if (ReadAttrTxt(elem, "texcoord", text)) {
|
||||
std::vector<float> texcoord = String2Vector<float>(text);
|
||||
mjs_setFloat(pflex->texcoord, texcoord.data(), texcoord.size());
|
||||
auto texcoord = ReadAttrVec<float>(elem, "texcoord");
|
||||
if (texcoord.has_value()) {
|
||||
mjs_setFloat(pflex->texcoord, texcoord->data(), texcoord->size());
|
||||
}
|
||||
|
||||
// contact subelement
|
||||
@@ -1459,21 +1459,21 @@ void mjXReader::OneSkin(XMLElement* elem, mjsSkin* pskin) {
|
||||
ReadAttr(elem, "inflate", 1, &pskin->inflate, text);
|
||||
|
||||
// read vertex data
|
||||
if (ReadAttrTxt(elem, "vertex", text)) {
|
||||
std::vector<float> vert = String2Vector<float>(text);
|
||||
mjs_setFloat(pskin->vert, vert.data(), vert.size());
|
||||
auto vertex = ReadAttrVec<float>(elem, "vertex");
|
||||
if (vertex.has_value()) {
|
||||
mjs_setFloat(pskin->vert, vertex->data(), vertex->size());
|
||||
}
|
||||
|
||||
// read texcoord data
|
||||
if (ReadAttrTxt(elem, "texcoord", text)) {
|
||||
std::vector<float> texcoord = String2Vector<float>(text);
|
||||
mjs_setFloat(pskin->texcoord, texcoord.data(), texcoord.size());
|
||||
auto texcoord = ReadAttrVec<float>(elem, "texcoord");
|
||||
if (texcoord.has_value()) {
|
||||
mjs_setFloat(pskin->texcoord, texcoord->data(), texcoord->size());
|
||||
}
|
||||
|
||||
// read user face data
|
||||
if (ReadAttrTxt(elem, "face", text)) {
|
||||
std::vector<int> face = String2Vector<int>(text);
|
||||
mjs_setInt(pskin->face, face.data(), face.size());
|
||||
auto face = ReadAttrVec<int>(elem, "face");
|
||||
if (face.has_value()) {
|
||||
mjs_setInt(pskin->face, face->data(), face->size());
|
||||
}
|
||||
|
||||
// read bones
|
||||
@@ -1500,14 +1500,16 @@ void mjXReader::OneSkin(XMLElement* elem, mjsSkin* pskin) {
|
||||
bindquat.push_back(data[3]);
|
||||
|
||||
// read vertid
|
||||
ReadAttrTxt(bone, "vertid", text, true);
|
||||
vector<int> tempid = String2Vector<int>(text);
|
||||
mjs_appendIntVec(pskin->vertid, tempid.data(), tempid.size());
|
||||
auto tempid = ReadAttrVec<int>(bone, "vertid", true);
|
||||
if (tempid.has_value()) {
|
||||
mjs_appendIntVec(pskin->vertid, tempid->data(), tempid->size());
|
||||
}
|
||||
|
||||
// read vertweight
|
||||
ReadAttrTxt(bone, "vertweight", text, true);
|
||||
vector<float> tempweight = String2Vector<float>(text);
|
||||
mjs_appendFloatVec(pskin->vertweight, tempweight.data(), tempweight.size());
|
||||
auto tempweight = ReadAttrVec<float>(bone, "vertweight", true);
|
||||
if (tempweight.has_value()) {
|
||||
mjs_appendFloatVec(pskin->vertweight, tempweight->data(), tempweight->size());
|
||||
}
|
||||
|
||||
// advance to next bone
|
||||
bone = NextSiblingElement(bone, "bone");
|
||||
@@ -2287,8 +2289,9 @@ void mjXReader::OneComposite(XMLElement* elem, mjsBody* pbody, mjsDefault* def)
|
||||
ReadAttrTxt(elem, "curve", curves);
|
||||
ReadAttrTxt(elem, "initial", comp.initial);
|
||||
ReadAttr(elem, "size", 3, comp.size, text, false, false);
|
||||
if (ReadAttrTxt(elem, "vertex", text)) {
|
||||
comp.uservert = String2Vector<float>(text);
|
||||
auto uservert = ReadAttrVec<float>(elem, "vertex");
|
||||
if (uservert.has_value()) {
|
||||
comp.uservert = std::move(uservert.value());
|
||||
}
|
||||
|
||||
// shell
|
||||
@@ -2530,14 +2533,17 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjsBody* pbody) {
|
||||
if (MapValue(elem, "rigid", &n, bool_map, 2)) {
|
||||
fcomp.rigid = (n==1);
|
||||
}
|
||||
if (ReadAttrTxt(elem, "point", text)){
|
||||
fcomp.point = String2Vector<double>(text);
|
||||
auto point = ReadAttrVec<double>(elem, "point");
|
||||
if (point.has_value()) {
|
||||
fcomp.point = std::move(point.value());
|
||||
}
|
||||
if (ReadAttrTxt(elem, "element", text)){
|
||||
fcomp.element = String2Vector<int>(text);
|
||||
auto element = ReadAttrVec<int>(elem, "element");
|
||||
if (element.has_value()) {
|
||||
fcomp.element = std::move(element.value());
|
||||
}
|
||||
if (ReadAttrTxt(elem, "texcoord", text)) {
|
||||
fcomp.texcoord = String2Vector<float>(text);
|
||||
auto texcoord = ReadAttrVec<float>(elem, "texcoord");
|
||||
if (texcoord.has_value()) {
|
||||
fcomp.texcoord = std::move(texcoord.value());
|
||||
}
|
||||
|
||||
// edge
|
||||
@@ -2575,23 +2581,22 @@ void mjXReader::OneFlexcomp(XMLElement* elem, mjsBody* pbody) {
|
||||
// pin
|
||||
XMLElement* epin = FirstChildElement(elem, "pin");
|
||||
while (epin) {
|
||||
// accumulate id, coord, range
|
||||
if (ReadAttrTxt(epin, "id", text)) {
|
||||
vector<int> v = String2Vector<int>(text);
|
||||
fcomp.pinid.insert(fcomp.pinid.end(), v.begin(), v.end());
|
||||
auto id = ReadAttrVec<int>(epin, "id");
|
||||
if (id.has_value()) {
|
||||
fcomp.pinid.insert(fcomp.pinid.end(), id->begin(), id->end());
|
||||
}
|
||||
if (ReadAttrTxt(epin, "range", text)) {
|
||||
vector<int> v = String2Vector<int>(text);
|
||||
fcomp.pinrange.insert(fcomp.pinrange.end(), v.begin(), v.end());
|
||||
auto range = ReadAttrVec<int>(epin, "range");
|
||||
if (range.has_value()) {
|
||||
fcomp.pinrange.insert(fcomp.pinrange.end(), range->begin(), range->end());
|
||||
}
|
||||
if (ReadAttrTxt(epin, "grid", text)) {
|
||||
|
||||
vector<int> v = String2Vector<int>(text);
|
||||
fcomp.pingrid.insert(fcomp.pingrid.end(), v.begin(), v.end());
|
||||
auto grid = ReadAttrVec<int>(epin, "grid");
|
||||
if (grid.has_value()) {
|
||||
fcomp.pingrid.insert(fcomp.pingrid.end(), grid->begin(), grid->end());
|
||||
}
|
||||
if (ReadAttrTxt(epin, "gridrange", text)) {
|
||||
vector<int> v = String2Vector<int>(text);
|
||||
fcomp.pingridrange.insert(fcomp.pingridrange.end(), v.begin(), v.end());
|
||||
auto gridrange = ReadAttrVec<int>(epin, "gridrange");
|
||||
if (gridrange.has_value()) {
|
||||
fcomp.pingridrange.insert(fcomp.pingridrange.end(),
|
||||
gridrange->begin(), gridrange->end());
|
||||
}
|
||||
|
||||
// advance
|
||||
|
||||
@@ -44,6 +44,7 @@ using std::string;
|
||||
using tinyxml2::XMLComment;
|
||||
using tinyxml2::XMLDocument;
|
||||
using tinyxml2::XMLElement;
|
||||
using mujoco::user::VectorToString;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -142,19 +143,19 @@ void mjXWriter::OneFlex(XMLElement* elem, const mjCFlex* pflex) {
|
||||
|
||||
// data vectors
|
||||
if (!pflex->get_vertbody().empty()) {
|
||||
Vector2String(text, pflex->get_vertbody());
|
||||
text = VectorToString(pflex->get_vertbody());
|
||||
WriteAttrTxt(elem, "body", text);
|
||||
}
|
||||
if (!pflex->get_vert().empty()) {
|
||||
Vector2String(text, pflex->get_vert());
|
||||
text = VectorToString(pflex->get_vert());
|
||||
WriteAttrTxt(elem, "vertex", text);
|
||||
}
|
||||
if (!pflex->get_elem().empty()) {
|
||||
Vector2String(text, pflex->get_elem());
|
||||
text = VectorToString(pflex->get_elem());
|
||||
WriteAttrTxt(elem, "element", text);
|
||||
}
|
||||
if (!pflex->get_texcoord().empty()) {
|
||||
Vector2String(text, pflex->get_texcoord());
|
||||
text = VectorToString(pflex->get_texcoord());
|
||||
WriteAttrTxt(elem, "texcoord", text);
|
||||
}
|
||||
|
||||
@@ -207,25 +208,25 @@ void mjXWriter::OneMesh(XMLElement* elem, const mjCMesh* pmesh, mjCDef* def) {
|
||||
|
||||
// write vertex data
|
||||
if (!pmesh->get_uservert().empty()) {
|
||||
Vector2String(text, pmesh->get_uservert());
|
||||
text = VectorToString(pmesh->get_uservert());
|
||||
WriteAttrTxt(elem, "vertex", text);
|
||||
}
|
||||
|
||||
// write normal data
|
||||
if (!pmesh->get_usernormal().empty()) {
|
||||
Vector2String(text, pmesh->get_usernormal());
|
||||
text = VectorToString(pmesh->get_usernormal());
|
||||
WriteAttrTxt(elem, "normal", text);
|
||||
}
|
||||
|
||||
// write texcoord data
|
||||
if (!pmesh->get_usertexcoord().empty()) {
|
||||
Vector2String(text, pmesh->get_usertexcoord());
|
||||
text = VectorToString(pmesh->get_usertexcoord());
|
||||
WriteAttrTxt(elem, "texcoord", text);
|
||||
}
|
||||
|
||||
// write face data
|
||||
if (!pmesh->get_userface().empty()) {
|
||||
Vector2String(text, pmesh->get_userface());
|
||||
text = VectorToString(pmesh->get_userface());
|
||||
WriteAttrTxt(elem, "face", text);
|
||||
}
|
||||
}
|
||||
@@ -257,17 +258,17 @@ void mjXWriter::OneSkin(XMLElement* elem, const mjCSkin* pskin) {
|
||||
// write data if no file
|
||||
if (pskin->get_file().empty()) {
|
||||
// mesh vert
|
||||
Vector2String(text, pskin->get_vert());
|
||||
text = VectorToString(pskin->get_vert());
|
||||
WriteAttrTxt(elem, "vertex", text);
|
||||
|
||||
// mesh texcoord
|
||||
if (!pskin->get_texcoord().empty()) {
|
||||
Vector2String(text, pskin->get_texcoord());
|
||||
text = VectorToString(pskin->get_texcoord());
|
||||
WriteAttrTxt(elem, "texcoord", text);
|
||||
}
|
||||
|
||||
// mesh face
|
||||
Vector2String(text, pskin->get_face());
|
||||
text = VectorToString(pskin->get_face());
|
||||
WriteAttrTxt(elem, "face", text);
|
||||
|
||||
// bones
|
||||
@@ -281,11 +282,11 @@ void mjXWriter::OneSkin(XMLElement* elem, const mjCSkin* pskin) {
|
||||
WriteAttr(bone, "bindquat", 4, pskin->get_bindquat().data()+4*i);
|
||||
|
||||
// write vertid
|
||||
Vector2String(text, pskin->get_vertid()[i]);
|
||||
text = VectorToString(pskin->get_vertid()[i]);
|
||||
WriteAttrTxt(bone, "vertid", text);
|
||||
|
||||
// write vertweight
|
||||
Vector2String(text, pskin->get_vertweight()[i]);
|
||||
text = VectorToString(pskin->get_vertweight()[i]);
|
||||
WriteAttrTxt(bone, "vertweight", text);
|
||||
}
|
||||
}
|
||||
|
||||
+47
-138
@@ -43,10 +43,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
using std::size_t;
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
using std::vector;
|
||||
using tinyxml2::XMLAttribute;
|
||||
using tinyxml2::XMLElement;
|
||||
|
||||
@@ -238,7 +234,7 @@ mjXSchema::mjXSchema(const char* schema[][mjXATTRNUM], unsigned nrow) {
|
||||
|
||||
|
||||
// get pointer to error message
|
||||
string mjXSchema::GetError() {
|
||||
std::string mjXSchema::GetError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -256,7 +252,7 @@ static void printspace(std::stringstream& str, int n, const char* space) {
|
||||
// print schema as text
|
||||
void mjXSchema::Print(std::stringstream& str, int level) const {
|
||||
// replace body with (world)body
|
||||
string name1 = (name_ == "body") ? "(world)body" : name_;
|
||||
std::string name1 = (name_ == "body") ? "(world)body" : name_;
|
||||
|
||||
// space, name, type
|
||||
printspace(str, 3*level, " ");
|
||||
@@ -290,7 +286,7 @@ void mjXSchema::Print(std::stringstream& str, int level) const {
|
||||
// print schema as HTML table
|
||||
void mjXSchema::PrintHTML(std::stringstream& str, int level, bool pad) const {
|
||||
// replace body with (world)body
|
||||
string name1 = (name_ == "body" ? "(world)body" : name_);
|
||||
std::string name1 = (name_ == "body" ? "(world)body" : name_);
|
||||
|
||||
// open table
|
||||
if (level==0) {
|
||||
@@ -377,7 +373,7 @@ XMLElement* mjXSchema::Check(XMLElement* elem, int level) {
|
||||
const XMLAttribute* attribute = elem->FirstAttribute();
|
||||
for (; attribute != nullptr; attribute = attribute->Next()) {
|
||||
if (attr_.find(attribute->Name()) == attr_.end()) {
|
||||
error = "unrecognized attribute: '" + string(attribute->Name()) + "'";
|
||||
error = "unrecognized attribute: '" + std::string(attribute->Name()) + "'";
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
@@ -541,7 +537,7 @@ template bool mjXUtil::SameVector(const unsigned char* vec1, const unsigned char
|
||||
|
||||
|
||||
// find string in map, return corresponding integer (-1: not found)
|
||||
int mjXUtil::FindKey(const mjMap* map, int mapsz, string key) {
|
||||
int mjXUtil::FindKey(const mjMap* map, int mapsz, std::string key) {
|
||||
for (int i=0; i<mapsz; i++) {
|
||||
if (map[i].key == key) {
|
||||
return map[i].value;
|
||||
@@ -554,7 +550,7 @@ int mjXUtil::FindKey(const mjMap* map, int mapsz, string key) {
|
||||
|
||||
|
||||
// find integer in map, return corresponding string ("": not found)
|
||||
string mjXUtil::FindValue(const mjMap* map, int mapsz, int value) {
|
||||
std::string mjXUtil::FindValue(const mjMap* map, int mapsz, int value) {
|
||||
for (int i=0; i<mapsz; i++) {
|
||||
if (map[i].value == value) {
|
||||
return map[i].key;
|
||||
@@ -570,9 +566,22 @@ string mjXUtil::FindValue(const mjMap* map, int mapsz, int value) {
|
||||
template<typename T>
|
||||
std::optional<std::vector<T>> mjXUtil::ReadAttrVec(XMLElement* elem, const char* attr,
|
||||
bool required) {
|
||||
std::vector<T> vec;
|
||||
ReadAttrValues<T>(elem, attr, [&](int i, T num) { vec.push_back(num); });
|
||||
if (!vec.size()) {
|
||||
std::vector<T> v;
|
||||
const char* raw_cstr = elem->Attribute(attr);
|
||||
if (raw_cstr) {
|
||||
v = mujoco::user::StringToVector<T>(raw_cstr);
|
||||
if (errno == EDOM) {
|
||||
mju_warning("XML contains a 'NaN'. Please check it carefully.");
|
||||
} else if (errno == ERANGE) {
|
||||
throw mjXError(elem, "number is too large in attribute '%s'", attr);
|
||||
} else if (errno == EINVAL) {
|
||||
throw mjXError(elem, "bad format in attribute '%s'", attr);
|
||||
} else if (errno != 0) {
|
||||
throw mjXError(elem, "unknown error in attribute '%s'", attr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!v.size()) {
|
||||
if (required) {
|
||||
throw mjXError(elem, "required attribute missing: '%s'", attr);
|
||||
} else {
|
||||
@@ -580,7 +589,7 @@ std::optional<std::vector<T>> mjXUtil::ReadAttrVec(XMLElement* elem, const char*
|
||||
}
|
||||
}
|
||||
|
||||
return vec;
|
||||
return v;
|
||||
}
|
||||
|
||||
template std::optional<std::vector<double>>
|
||||
@@ -651,7 +660,7 @@ mjXUtil::ReadAttrNum(XMLElement* elem, const char* attr, bool required);
|
||||
// return number of elements found
|
||||
template<typename T>
|
||||
int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
|
||||
T* data, string& text, bool required, bool exact) {
|
||||
T* data, std::string& text, bool required, bool exact) {
|
||||
auto maybe_vec = ReadAttrVec<T>(elem, attr, required);
|
||||
if (!maybe_vec.has_value()) {
|
||||
return 0;
|
||||
@@ -672,21 +681,21 @@ int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, const int len,
|
||||
}
|
||||
|
||||
template int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, int len,
|
||||
double* data, string& text, bool required, bool exact);
|
||||
double* data, std::string& text, bool required, bool exact);
|
||||
|
||||
template int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, int len,
|
||||
float* data, string& text, bool required, bool exact);
|
||||
float* data, std::string& text, bool required, bool exact);
|
||||
|
||||
template int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, int len,
|
||||
int* data, string& text, bool required, bool exact);
|
||||
int* data, std::string& text, bool required, bool exact);
|
||||
|
||||
template int mjXUtil::ReadAttr(XMLElement* elem, const char* attr, int len,
|
||||
unsigned char* data, string& text, bool required,
|
||||
unsigned char* data, std::string& text, bool required,
|
||||
bool exact);
|
||||
|
||||
// read quaternion attribute
|
||||
// throw error if identically zero
|
||||
int mjXUtil::ReadQuat(XMLElement* elem, const char* attr, double* data, string& text,
|
||||
int mjXUtil::ReadQuat(XMLElement* elem, const char* attr, double* data, std::string& text,
|
||||
bool required) {
|
||||
ReadAttr(elem, attr, /*len=*/4, data, text, required, /*exact=*/true);
|
||||
|
||||
@@ -700,7 +709,7 @@ int mjXUtil::ReadQuat(XMLElement* elem, const char* attr, double* data, string&
|
||||
|
||||
// read DOUBLE array into C++ vector, return number read
|
||||
int mjXUtil::ReadVector(XMLElement* elem, const char* attr,
|
||||
vector<double>& vec, string& text, bool required) {
|
||||
std::vector<double>& vec, std::string& text, bool required) {
|
||||
auto maybe_vec = ReadAttrVec<double>(elem, attr, required);
|
||||
if (!maybe_vec.has_value()) {
|
||||
return 0;
|
||||
@@ -713,7 +722,8 @@ int mjXUtil::ReadVector(XMLElement* elem, const char* attr,
|
||||
|
||||
|
||||
// read text field
|
||||
bool mjXUtil::ReadAttrTxt(tinyxml2::XMLElement* elem, const char* attr, string& text, bool required) {
|
||||
bool mjXUtil::ReadAttrTxt(tinyxml2::XMLElement* elem, const char* attr,
|
||||
std::string& text, bool required) {
|
||||
auto maybe_str = ReadAttrStr(elem, attr, required);
|
||||
if (!maybe_str.has_value()) {
|
||||
return false;
|
||||
@@ -735,92 +745,9 @@ bool mjXUtil::ReadAttrInt(XMLElement* elem, const char* attr, int* data, bool re
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<> int mjXUtil::StrToNum(char* str, char** c) {
|
||||
return std::strtol(str, c, 10);
|
||||
}
|
||||
|
||||
template<> float mjXUtil::StrToNum(char* str, char** c) {
|
||||
return std::strtof(str, c);
|
||||
}
|
||||
|
||||
template<> double mjXUtil::StrToNum(char* str, char** c) {
|
||||
return std::strtod(str, c);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> mjXUtil::String2Vector(const std::string& s) {
|
||||
errno = 0;
|
||||
std::vector<T> v;
|
||||
char* cs = (char*) s.c_str();
|
||||
char* ch = cs;
|
||||
|
||||
// reserve worst case
|
||||
v.reserve((s.size() >> 1) + 1);
|
||||
|
||||
for (;;) {
|
||||
cs = ch;
|
||||
T num = StrToNum<T>(cs, &ch);
|
||||
if (cs == ch) break;
|
||||
if (errno) break;
|
||||
v.push_back(num);
|
||||
}
|
||||
|
||||
v.shrink_to_fit();
|
||||
return v;
|
||||
}
|
||||
|
||||
template std::vector<int> mjXUtil::String2Vector(const std::string& s);
|
||||
template std::vector<float> mjXUtil::String2Vector(const std::string& s);
|
||||
template std::vector<double> mjXUtil::String2Vector(const std::string& s);
|
||||
template<>
|
||||
std::vector<std::string> mjXUtil::String2Vector(const std::string& s) {
|
||||
std::vector<std::string> v;
|
||||
std::stringstream ss(s);
|
||||
std::string word;
|
||||
while (ss >> word) {
|
||||
v.push_back(word);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// write vector<float> to string
|
||||
void mjXUtil::Vector2String(string& txt, const vector<string>& vec) {
|
||||
stringstream strm;
|
||||
|
||||
for (size_t i=0; i<vec.size(); i++) {
|
||||
if (i>0) {
|
||||
strm << " ";
|
||||
}
|
||||
strm << vec[i];
|
||||
}
|
||||
|
||||
txt = strm.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// write vector<double> to string
|
||||
void mjXUtil::Vector2String(string& txt, const vector<double>& vec) {
|
||||
stringstream strm;
|
||||
|
||||
for (size_t i=0; i<vec.size(); i++) {
|
||||
if (i>0) {
|
||||
strm << " ";
|
||||
}
|
||||
strm << vec[i];
|
||||
}
|
||||
|
||||
txt = strm.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// write vector<float> to string
|
||||
void mjXUtil::Vector2String(string& txt, const vector<float>& vec, int ncol) {
|
||||
stringstream strm;
|
||||
void mjXUtil::Vector2String(std::string& txt, const std::vector<float>& vec, int ncol) {
|
||||
std::stringstream strm;
|
||||
|
||||
for (size_t i=0; i<vec.size(); i++) {
|
||||
if (ncol && (i % ncol) == 0) {
|
||||
@@ -834,26 +761,8 @@ void mjXUtil::Vector2String(string& txt, const vector<float>& vec, int ncol) {
|
||||
txt = strm.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// write vector<int> to string
|
||||
void mjXUtil::Vector2String(string& txt, const vector<int>& vec) {
|
||||
stringstream strm;
|
||||
|
||||
for (size_t i=0; i<vec.size(); i++) {
|
||||
if (i>0) {
|
||||
strm << " ";
|
||||
}
|
||||
strm << vec[i];
|
||||
}
|
||||
|
||||
txt = strm.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// find subelement with given name, make sure it is unique
|
||||
XMLElement* mjXUtil::FindSubElem(XMLElement* elem, string name, bool required) {
|
||||
XMLElement* mjXUtil::FindSubElem(XMLElement* elem, std::string name, bool required) {
|
||||
XMLElement* subelem = 0;
|
||||
|
||||
XMLElement* iter = elem->FirstChildElement();
|
||||
@@ -924,7 +833,7 @@ static int Round(double x) {
|
||||
|
||||
// write attribute
|
||||
template<typename T>
|
||||
void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, const T* data, const T* def,
|
||||
void mjXUtil::WriteAttr(XMLElement* elem, std::string name, int n, const T* data, const T* def,
|
||||
bool trim) {
|
||||
// make sure all are defined
|
||||
if constexpr (std::is_floating_point_v<T>) {
|
||||
@@ -948,7 +857,7 @@ void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, const T* data, con
|
||||
}
|
||||
|
||||
// increase precision for testing
|
||||
stringstream stream;
|
||||
std::stringstream stream;
|
||||
stream.precision(mujoco::_mjPRIVATE__get_xml_precision());
|
||||
|
||||
// process all numbers
|
||||
@@ -972,22 +881,22 @@ void mjXUtil::WriteAttr(XMLElement* elem, string name, int n, const T* data, con
|
||||
}
|
||||
|
||||
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, std::string name, int n,
|
||||
const double* data, const double* def, bool trim);
|
||||
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, std::string name, int n,
|
||||
const float* data, const float* def, bool trim);
|
||||
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, std::string name, int n,
|
||||
const int* data, const int* def, bool trim);
|
||||
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, string name, int n,
|
||||
template void mjXUtil::WriteAttr(XMLElement* elem, std::string name, int n,
|
||||
const unsigned char* data,
|
||||
const unsigned char* def, bool trim);
|
||||
|
||||
|
||||
// write vector<double> attribute, default = zero array
|
||||
void mjXUtil::WriteVector(XMLElement* elem, string name, const vector<double>& vec) {
|
||||
void mjXUtil::WriteVector(XMLElement* elem, std::string name, const std::vector<double>& vec) {
|
||||
// proceed only if non-zero found
|
||||
bool ok = false;
|
||||
for (size_t i=0; i<vec.size(); i++) {
|
||||
@@ -1006,8 +915,8 @@ void mjXUtil::WriteVector(XMLElement* elem, string name, const vector<double>& v
|
||||
|
||||
|
||||
// write vector<double> attribute, default with same size
|
||||
void mjXUtil::WriteVector(XMLElement* elem, string name, const vector<double>& vec,
|
||||
const vector<double>& def) {
|
||||
void mjXUtil::WriteVector(XMLElement* elem, std::string name, const std::vector<double>& vec,
|
||||
const std::vector<double>& def) {
|
||||
// proceed only if non-zero found
|
||||
bool ok = false;
|
||||
for (size_t i=0; i<vec.size(); i++) {
|
||||
@@ -1026,7 +935,7 @@ void mjXUtil::WriteVector(XMLElement* elem, string name, const vector<double>& v
|
||||
|
||||
|
||||
// write attribute- string
|
||||
void mjXUtil::WriteAttrTxt(XMLElement* elem, string name, string value) {
|
||||
void mjXUtil::WriteAttrTxt(XMLElement* elem, std::string name, std::string value) {
|
||||
// skip if value is empty
|
||||
if (value.empty()) {
|
||||
return;
|
||||
@@ -1039,7 +948,7 @@ void mjXUtil::WriteAttrTxt(XMLElement* elem, string name, string value) {
|
||||
|
||||
|
||||
// write attribute- single int
|
||||
void mjXUtil::WriteAttrInt(XMLElement* elem, string name, int data, int def) {
|
||||
void mjXUtil::WriteAttrInt(XMLElement* elem, std::string name, int data, int def) {
|
||||
// skip default
|
||||
if (data==def) {
|
||||
return;
|
||||
@@ -1051,7 +960,7 @@ void mjXUtil::WriteAttrInt(XMLElement* elem, string name, int data, int def) {
|
||||
|
||||
|
||||
// write attribute- keyword
|
||||
void mjXUtil::WriteAttrKey(XMLElement* elem, string name,
|
||||
void mjXUtil::WriteAttrKey(XMLElement* elem, std::string name,
|
||||
const mjMap* map, int mapsz, int data, int def) {
|
||||
// skip default
|
||||
if (data==def) {
|
||||
|
||||
@@ -163,21 +163,9 @@ class mjXUtil {
|
||||
static bool ReadAttrInt(tinyxml2::XMLElement* elem, const char* attr, int* data,
|
||||
bool required = false);
|
||||
|
||||
// convert string to vector
|
||||
template<typename T>
|
||||
static std::vector<T> String2Vector(const std::string& s);
|
||||
|
||||
// write vector<string> to string
|
||||
static void Vector2String(std::string& txt, const std::vector<std::string>& vec);
|
||||
|
||||
// write vector<double> to string
|
||||
static void Vector2String(std::string& txt, const std::vector<double>& vec);
|
||||
|
||||
// write vector<float> to string
|
||||
static void Vector2String(std::string& txt, const std::vector<float>& vec, int ncol = 0);
|
||||
|
||||
// write vector<int> to string
|
||||
static void Vector2String(std::string& txt, const std::vector<int>& vec);
|
||||
|
||||
// find subelement with given name, make sure it is unique
|
||||
static tinyxml2::XMLElement* FindSubElem(tinyxml2::XMLElement* elem, std::string name,
|
||||
@@ -212,8 +200,6 @@ class mjXUtil {
|
||||
template<typename T>
|
||||
static bool ReadAttrValues(tinyxml2::XMLElement* elem, const char* attr,
|
||||
std::function<void (int, T)> push, int max = -1);
|
||||
template<typename T> static T StrToNum(char* str, char** c);
|
||||
|
||||
};
|
||||
|
||||
#endif // MUJOCO_SRC_XML_XML_UTIL_H_
|
||||
|
||||
Reference in New Issue
Block a user