I am trying to create a boost graph of robot joint configuration space. For that I am using custom VertexProperty.
struct VertexProperties {
std::vector<double> joint_angles;
VertexProperties() : joint_angles(3){}
};
I have saved the graph using write_graphML with below implementation
std::string BoostGraph::vertexJointAngles(Vertex& v){
std::ostringstream sstream;
std::vector<double> jointAngles(graph[v].joint_angles);
for (std::size_t i = 0; i < jointAngles.size(); i++){
sstream << jointAngles[i];
if(i != jointAngles.size()-1) sstream << ',';
}
return sstream.str();
}
```
void BoostGraph::printGraphML(std::ostream &out){
boost::function_property_map<std::function<std::string(Vertex)>, Vertex> jointAngles([this](Vertex v)
{
return vertexJointAngles(v);
});
});
boost::dynamic_properties dp;
dp.property("Joint_Angles", jointAngles);
dp.property("edge_weight", boost::get(&EdgeProperties::weight, graph));
boost::write_graphml(out, graph, dp);
}
Now I need to read the graph again in another BoostGraph class instance for query and A* search. How can I convert the joint angles saved as string in graphml to vertex property?
I tried the below implementation ( I am just starting in Boost) but its not working.
std::vector<double> BoostGraph::readJointAngles(std::string joint_angle_string){
std::stringstream ss;
ss << joint_angle_string;
std::vector<double> joint_angle;
double number;
while (ss >> number)
joint_angle.push_back(number);
return joint_angle;
}
void BoostGraph::readGraphGraphML(std::istream& file){
boost::dynamic_properties dp;
boost::function_property_map<std::function<std::vector<double>(std::string)>, Vertex> jointAngles([this](std::string v)
{
return readJointAngles(v);
});
dp.property("Joint_Angles", jointAngles );
dp.property("edge_weight", boost::get(&EdgeProperties::weight, graph));
boost::read_graphml(file, graph, dp);
}
Good starting point there. Nice job.
Therefore I'm going to jump immediately to the pain point:
Writable property maps have to return something that models lvalue semantics. Your
readJointAnglesassumes a "procedural" conversion task instead. That's not a property map.My first thought is to stay close to the concept of the property map by combining the read and write into a proxy class. The proxy class can be
VertexPropertiesitself, but as I can imagineVertexPropertieshaving multiple members with similar requirements, let me do the "pure" thing and have it separate here:Now you can replace the function property-map:
And the output will still be identical. Actually, we have a more light-weight property map abstraction that fits the bill even more elegantly:
A Road Bump
However,
function_property_mapis still not an lvalue-property map. That's sad.Turns out I forgot about this snag. I've written about this rather central issue with
read_graphml(or withdynamic_properties, really) before:The approach I took there was to create my own
ReadWritePropertyMap. Which is sensible, given that it essentially merges into what we already have above (JointAngleWrapper).Now you can use it with success:
Which successfully roundtrips a "random" graph:
Prints
Full Listing
Live On Coliru