Skip to content

Commit 3f03162

Browse files
committed
Sdf to Dot generator
1 parent dd2d147 commit 3f03162

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed

subt_ign/src/dot_generator.cc

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* Copyright (C) 2020 Open Source Robotics Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
#include <ignition/common/Console.hh>
19+
#include "ConnectionHelper.hh"
20+
21+
using namespace ignition;
22+
using namespace subt;
23+
24+
/// \brief Parse contents of an sdf element
25+
/// \param[in] _key SDF element key
26+
/// \param[in] _str String content of the sdf element
27+
/// \param[out] _endPos end position of the sdf element string
28+
/// \return Value for the input key
29+
std::string parse(const std::string _key, const std::string &_str,
30+
size_t &_endPos)
31+
{
32+
std::string elemStartStr = "<" + _key + ">";
33+
std::string elemEndStr = "</" + _key + ">";
34+
35+
size_t start = _str.find(elemStartStr);
36+
if (start == std::string::npos)
37+
return std::string();
38+
size_t startIdx = start + elemStartStr.size();
39+
size_t end = _str.find(elemEndStr, startIdx);
40+
if (end == std::string::npos)
41+
return std::string();
42+
43+
_endPos = end + elemEndStr.size();
44+
std::string result = _str.substr(startIdx, end - startIdx);
45+
return result;
46+
}
47+
48+
/// \brief Parse contents of an sdf element
49+
/// \param[in] _key SDF element key
50+
/// \param[in] _str String content of the sdf element
51+
/// \return Value for the input key
52+
std::string parse(const std::string _key, const std::string &_str)
53+
{
54+
size_t endPos;
55+
return parse(_key, _str, endPos);
56+
}
57+
58+
/// \brief Print the DOT file
59+
/// \param[in] _vertexData vector of vertex data containing
60+
/// vertex and edge info
61+
void printGraph(std::vector<VertexData> &_vertexData)
62+
{
63+
std::stringstream out;
64+
out << "graph {\n";
65+
out << "/* ==== Vertices ==== */\n";
66+
// out << "0 [label=\"0::base_station::BaseStation\"]\n";
67+
68+
for (auto &vd : _vertexData)
69+
{
70+
// update staging area name for compatibility with other subt tools that
71+
// rely on this naming convention
72+
std::string name = vd.tileName;
73+
std::string type = vd.tileType;
74+
if (type == "Cave Starting Area" ||
75+
type == "Urban Starting Area")
76+
{
77+
type = "base_station";
78+
name = "BaseStation";
79+
}
80+
out << vd.id << " " << "[label=\"" << vd.id << "::" << type
81+
<< "::" << name << "\"];\n";
82+
}
83+
84+
out << "/* ==== Edges ==== */\n";
85+
86+
for (unsigned int i = 0u; i < _vertexData.size() -1; ++i)
87+
{
88+
for (unsigned int j = i+1; j < _vertexData.size(); ++j)
89+
{
90+
math::Vector3d point;
91+
if (subt::ConnectionHelper::ComputePoint(
92+
&_vertexData[i], &_vertexData[j], point))
93+
{
94+
int cost = 1;
95+
auto tp1 =
96+
subt::ConnectionHelper::connectionTypes[_vertexData[i].tileType];
97+
auto tp2 =
98+
subt::ConnectionHelper::connectionTypes[_vertexData[j].tileType];
99+
if (tp1 == subt::ConnectionHelper::STRAIGHT &&
100+
tp2 == subt::ConnectionHelper::STRAIGHT)
101+
cost = 1;
102+
else if (tp1 == subt::ConnectionHelper::TURN &&
103+
tp2 == subt::ConnectionHelper::STRAIGHT)
104+
cost = 3;
105+
else if (tp1 == subt::ConnectionHelper::STRAIGHT &&
106+
tp2 == subt::ConnectionHelper::TURN)
107+
cost = 3;
108+
else
109+
cost = 6;
110+
111+
out << _vertexData[i].id << " -- " << _vertexData[j].id
112+
<< " " << "[label=" << cost << "];\n" ;
113+
}
114+
}
115+
}
116+
117+
out << "}";
118+
std::cout << out.str() << std::endl;
119+
}
120+
121+
/// \brief Fill VertexData from string
122+
/// \param[in] _includeStr input <include> string
123+
/// \param[out] _vd Vertex data to be filled
124+
/// \return True if vertex data is successfully filled, false otherwise
125+
bool fillVertexData(const std::string &_includeStr, VertexData &_vd)
126+
{
127+
// parse name
128+
std::string name = parse("name", _includeStr);
129+
130+
// parse pose
131+
std::string poseStr = parse("pose", _includeStr);
132+
math::Pose3d pose;
133+
std::stringstream ss(poseStr);
134+
ss >> pose;
135+
136+
// parse uri and get model type
137+
std::string uri = parse("uri", _includeStr);
138+
std::string fuelStr =
139+
"https://fuel.ignitionrobotics.org/1.0/openrobotics/models/";
140+
size_t fuelIdx = uri.find(fuelStr);
141+
std::string modelType;
142+
if (fuelIdx == std::string::npos)
143+
return false;
144+
modelType = uri.substr(fuelIdx + fuelStr.size());
145+
146+
// check if model type is recognized
147+
if (subt::ConnectionHelper::connectionPoints.count(modelType) <= 0)
148+
return false;
149+
sdf::Model modelSdf;
150+
modelSdf.SetName(name);
151+
modelSdf.SetPose(pose);
152+
153+
static int tileId = 0;
154+
_vd.id = tileId++;
155+
_vd.tileType = modelType;
156+
_vd.tileName = name;
157+
_vd.model = modelSdf;
158+
159+
return true;
160+
}
161+
162+
/// \brief Main function to generat DOT from input sdf file
163+
/// \param[in] _sdfFile Input sdf file.
164+
void generateDOT(const std::string &_sdfFile)
165+
{
166+
std::ifstream file(_sdfFile);
167+
if (!file.is_open())
168+
{
169+
std::cerr << "Failed to read file " << _sdfFile << std::endl;
170+
return;
171+
}
172+
std::string str((std::istreambuf_iterator<char>(file)),
173+
std::istreambuf_iterator<char>());
174+
175+
std::vector<VertexData> vertexData;
176+
while (!str.empty())
177+
{
178+
size_t result = std::string::npos;
179+
std::string includeStr = parse("include", str, result);
180+
if (result == std::string::npos || result > str.size())
181+
break;
182+
183+
VertexData vd;
184+
bool filled = fillVertexData(includeStr, vd);
185+
if (filled)
186+
vertexData.push_back(vd);
187+
188+
str = str.substr(result);
189+
}
190+
191+
printGraph(vertexData);
192+
193+
file.close();
194+
}
195+
196+
//////////////////////////////////////////////////
197+
int main(int argc, char **argv)
198+
{
199+
if (argc < 2)
200+
{
201+
std::cerr << "Usage: dot_generator <path_to_world_sdf_file>"
202+
<< std::endl;
203+
return -1;
204+
}
205+
std::string sdfFile = argv[1];
206+
generateDOT(sdfFile);
207+
208+
return 0;
209+
}

0 commit comments

Comments
 (0)