Writing boost dynamic properties to a file using Boost Graph Library - c++

I have already asked a question here about using Boost Graph Library and writing graph into file. Due to change in my requirements, I need to write dynamic graph properties into a DOT file. After some look up, I managed to come up with some code but it does not work. Below is what I have done so far:
Map class uses the Cell class as vertices and Cell class uses a separate CellProperty class for setting and getting all the Cell properties.
And finally Map class where I build the graph and try to write the graph into a DOT file.
Map.h
class Map {
public:
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::undirectedS, Cell> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
explicit Map(std::string pGraphFilePath);
virtual ~Map();
void LoadGraph();
private:
Graph mGraph;
std::vector<std::vector<Vertex>> mGrid;
};
Map.cpp
const unsigned int RowNum = 3;
const unsigned int ColumnNum = 4;
Map::Map(std::string pGraphFilePath) : mGraph(), mGrid() {}
Map::~Map() {}
void Map::LoadGraph() {
int dummyID = 1;
for (unsigned int row = 0; row < RowNum; row++) {
mGrid.resize(RowNum);
for (unsigned int col = 0; col < ColumnNum; col++) {
mGrid[row].resize(ColumnNum);
Vertex vID = boost::add_vertex(mGraph);
mGraph[vID].SetProperty<unsigned int>("ID", dummyID);
mGraph[vID].SetProperty<bool>("Navigable", true);
mGrid[row][col] = vID;
dummyID++;
// add the edges for the contained cells in the grid
if (col > 0) { boost::add_edge(mGrid[row][col - 1], mGrid[row][col], mGraph); }
if (row > 0) { boost::add_edge(mGrid[row - 1][col], mGrid[row][col], mGraph); }
}
}
// write cell properties
boost::dynamic_properties propertiesOutPut;
propertiesOutPut.property("ID", boost::get(boost::vertex_index, mGraph));
// As Navigable is an external property, it need to be mapped with the internal graph property
// the lines below are the update after I got the answers and link for my query
// cell.GetProperty() is a templated method the takes a default parameter, thus passing "false" bool parameter which returns the "Navigable" cell property
auto valueNavigable = boost::make_transform_value_property_map([](Cell &cell) { return cell.GetProperty<bool>("Navigable", false); }, boost::get(boost::vertex_bundle, mGraph));
propertiesOutPut.property("Navigable", valueNavigable);
std::ofstream fout("MyGraph.dot");
boost::write_graphviz_dp(fout, mGraph, propertiesOutPut, std::string("ID"));
}
The problem I am getting is with the propertiesOutPut.property() method for boost::get(). I can not figure out the correct parameters for boost::get(). Please help me out. Thanks !!

You could use a transform_value_property_map on top of the propertymap that contains the vertex properties struct. (You didn't show it).
I have a number of answers showing how to do that, although these are all using internal properties, there is no big difference because anu property map can be transformed in the same way, regardless of whether the property map is internal or external (that's the whole purpose of property maps: decoupling the way properties are accessed).
Most relevant:
Overloading streaming operators for a Boost Graph bundle output for GraphViz
Manually colouring of boost's graphs
Other:
see these search results: https://stackoverflow.com/search?tab=votes&q=user%3a85371%20make_transform_value_property_map

Related

How to get vertex from boost graph in constant time?

I'm trying to create a graph where lanes represent vertices and edges connections between. The idea is to later on use a_star algorithm to traverse the graph and find the best route.
My question is how can I get vertex (descriptor?) by using just (town_id, road_id, lane_id)?
I tryied battling with the examples that are shipped with boost and basically lost. In them they always traverse thru all the vertices and then get the vertex_descriptor, but I want to do that in constant time.
What is need is something like boost::get_vertex(std::tuple(1, 2, 3), graph).
My situation is marked as PROBLEM bellow in the code. The code bellow compiles because there is 12 that I guess corresponds to the index in boost::vecS, but I want to use a tuple (or something else that can hold the triplet) that could get me the vertex descriptor as my starting location.
using TRL = std::tuple<int, int, int>;
struct TRL_VProp {
/// For some reason this object has to be default constructable
/// use invalid data to flag it as invalid
TRL_VProp()
: trl(-1, -1, 0) {}
TRL_VProp(TRL trl)
: trl(trl) {}
TRL_VProp(int town_id, int road_id, int lane_id)
: trl(town_id, road_id, lane_id) {}
TRL trl;
};
using DirectedGraph = boost::adjacency_list<boost::listS,
boost::vecS,
boost::directedS,
RSL_VProp>;
using Vertex = boost::graph_traits<DirectedGraph>::vertex_descriptor;
using VertexI = boost::graph_traits<DirectedGraph>::vertex_iterator;
using EdgeI = boost::graph_traits<DirectedGraph>::edge_iterator;
using Edge = boost::graph_traits<DirectedGraph>::edge_descriptor;
using AdjI = boost::graph_traits<DirectedGraph>::adjacency_iterator;
using Route = std:vector<TRL>;
Route BuildRoute(Map & map) {
Route result;
DirectedGraph graph;
const boost::property_map<DirectedGraph, RSL RSL_VProp:: *>::type trl =
boost::get(&TRL_VProp::rsl, graph);
bool is_inserted;
Edge e_desc;
for (auto & town: map.GetTowns()) {
for (auto & road: town.GetRoads()) {
for (auto & lane: road.GetLanes()) {
auto vtx_1 = boost::add_vertex(
RSL_VProp(town.GetId(), road.GetId(), lane.GetId()),
graph);
const auto next_lanes = map.GetNextLanes(town.GetId(), road.GetId(), lane.GetId());
for(const auto & next_lane : next_lanes) {
auto vtx_2 = boost::add_vertex(
TRL_VProp(lane.GetTown().GetId(), lane.GetRoad().GetId(), lane.GetId()),
graph);
std::tie(e_desc, is_inserted) = boost::add_edge(vtx_1, vtx_2, graph);
assert(is_inserted);
}
}
}
}
// debug part
TRL temp_trl;
std::pair<AdjI, AdjI> adj_i = boost::adjacent_vertices(12, graph); // <--- PROBLEM
for( auto i = adj_i.first; i != adj_i.second; i++) {
temp_trl = trl[*i]; // trl prop map
std:: cout << "\Town id: " << std::get<0>(temp_trl)
<< "\nRoad id: " << std::get<1>(temp_trl)
<< "\nLane id: " << std::get<2>(temp_trl);
result.push_back(
std::make_tuple(
std::get<0>(temp_trl),
std::get<1>(temp_trl),
std::get<2>(temp_trl)));
}
return result;
}
For completeness, I don't plan to change data inside the property or the graph itself. Once thing is created it will probably stay that way. Maybe lateron I'll probably have to add the weight or whatever is necessary to get the traversing algorithm to work.
Edit: I forgot to mention that there is a bug in the code because I'm adding vertices before checking was vertex with identical (town, road, lane) already been created. I wonder is there a builtin boost::graph way to not insert duplicated so I won't have to use a std::unordered_map or something.

multiple lists into a map

I had a question regarding my code below. I'm reading a file containing lots of data of which some stuff is irrelevant. The data is written out on one line, so I cannot use nextLine or something.
For each vertex, I save the relevant information into dataperpoint. When I go to the next vertex, I want to clear the list to fill it with new relevant information.
The issue that I have is that each time I clear dataperpoint, all values in Map get cleared. When I then try to fill it, all previous positions in the Map get the same values.
How can I do this and make sure that each vertex will get his own list?
Looking forward to your suggestions!
public static Map<Integer, List<Double>> readData(File f) // throws IO exception?
{
// Create Map to store the vertex and list with relevant information in
List<Double> dataperpoint = new ArrayList<Double>();
Map<Integer, List<Double>> data = new HashMap<>();
// Open the scanner
try (Scanner in = new Scanner(f))
{
// To make sure the correct localization is used
in.useLocale(Locale.US);
// The first six integers contain irrelevant information
for (int step = 1; step <= 6; step++)
{
in.nextInt();
}
// Do the information for vertex 0 separately, since it has one data point less
int vertex = in.nextInt();
for (int doubleinfo = 1; doubleinfo <= 4; doubleinfo++) // six relevant variables
{
dataperpoint.add(in.nextDouble());
}
// irrelevant information
for (int irrelevantinfo = 1; irrelevantinfo <= 2; irrelevantinfo++)
{
in.nextInt();
}
// Opening and Closing of time window
dataperpoint.add((double) in.nextInt());
dataperpoint.add((double) in.nextInt());
data.put(vertex, dataperpoint);
while (in.hasNext()) // think of different statement later
{
dataperpoint = new ArrayList<Double>();
vertex = in.nextInt();
for (int doubleinfo = 1; doubleinfo <= 4; doubleinfo++) // six relevant variables
{
dataperpoint.add(in.nextDouble());
}
// irrelevant information
for (int irrelevantinfo = 1; irrelevantinfo <= 3; irrelevantinfo++)
{
in.nextInt();
}
// Opening and Closing of time window
dataperpoint.add((double) in.nextInt());
dataperpoint.add((double) in.nextInt());
data.put(vertex, dataperpoint);
}
in.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
Use LinkedHashMap<> instead of HashMap<> it should solve your problem. Read this Difference between HashMap, LinkedHashMap and TreeMap

Keyframing in 3DS MAX 2014 SDK c++

I want to ask you guys to help me with creating keyframes in Max SDK C++.
What I've done:
Created a Controller Plugin
Inside the getValue function I've done my translations via code.
I also wrote the setValue function.
Which I think manages keyframes and stores the controllers position in a given time in a given keyframe. In this way I achieved to be able to set keys manually, but I really would like, to work with the Auto Key turned on in Max.
On the other hand, I can't see the freshly added keys values. So please help me, how could I add keyframes?
Many Thanks:
Banderas
void maxProject3::GetValue(TimeValue t, void *ptr, Interval &valid, GetSetMethod method)
{
Point3 p3OurAbsValue(0, 0, 0);
tomb[0]=0;
//These positions stores my data they are globals
XPosition += (accX);
YPosition += (accY);
ZPosition += (accZ);
p3OurAbsValue.x = XPosition;
p3OurAbsValue.y = YPosition;
p3OurAbsValue.z = ZPosition;
valid.Set(t,t+1); //This answer is only valid at the calling time.
MatrixCtrl->GetValue(t, &p3OurAbsValue.y, valid, CTRL_RELATIVE);
if (method == CTRL_ABSOLUTE)
{
Point3* p3InVal = (Point3*)ptr;
*p3InVal = p3OurAbsValue;
}
else // CTRL_RELATIVE
{
//We do our translations on a Matrix
Matrix3* m3InVal = (Matrix3*)ptr;
//m3InVal->PreTranslate(p3OurAbsValue);
m3InVal->PreRotateX(rotX);
m3InVal->PreRotateY(rotY);
m3InVal->PreRotateZ(rotZ);
}
}
int maxProject3::NumSubs() {
return 1;
}
Animatable* maxProject3::SubAnim(int n) {
return MatrixCtrl;
}
void maxProject3::SetValue(TimeValue t, void *ptr, int commit, GetSetMethod method)
{
Matrix3* m3InVal = (Matrix3*)ptr;
MatrixCtrl->AddNewKey(t, ADDKEY_SELECT);
MatrixCtrl->SetValue(t, &m3InVal, commit, CTRL_RELATIVE);
}
To turn on the Auto key mode try using AnimateOn() before your transformation. Also add AnimateOff() to turn off the auto key mode in the end.
I did it in one of my project to create material id animation using auto key mode.
/** Auto key on*/
AnimateOn();
/** Creating material id animation */
for(int mtl_id = 1; mtl_id <= num_sub_mtl; ++mtl_id, time += time_step)
{
mtl_modifier->GetParamBlock()->SetValue(MATMOD_MATID,time,mtl_id);
}
/** Auto key off*/
AnimateOff();
Also as a suggestion, use the max script listener to know whats happening when the animation is created using 3ds Max GUI. This will help you to recreate the animation using Max SDK.

Accessing a property of a pointer in a struct

First of I have 2 Classes in 2 files (both .h and .cpp files), Create.h and AI.h.
Create.h has this struct in it:
public:
struct Cell
{
int row;
int column;
vector<Cell*> neighbors;
State state;
};
Here is the enum class State (stored in the Create.h file):
enum class State : char
{
visited,
empty
};
In AI.h I have a stack and a Create object like this:
private:
deque<Create::Cell*> path;
Create obj;
In AI.cpp there is an instance called obj which contains a 2D array of Cell where every Cell has row, column, state and neighbors set appropriately.
Constructor:
AI::AI(Create createObj)
: obj(createObj)
{
start = &obj.array[1][1];
}
I also have a function like this which starts with start as an argument:
void AI::Function(Create::Cell* cell)
{
path.push_back(cell);
cell->state = State::visited;
while (expression)
{
cell = path.back();
cell->state = State::visited;
for (int i = 0; i < cell->neighbors.size(); i++)
{
if (cell->neighbors[i]->state == State::empty)
{
path.push_back(cell->neighbors[i]);
}
}
}
}
So basically the cell in the path stack starts by pointing to the obj.array[1][1] and sets it correctly (I have confirmed that it actually points where I want it to) but when I retrieve a cell from the stack it doesn't point to the obj.array.
What I am trying to do is to set the state of the neighbors of each cell but I manage to set the state on the path stack, on the cell itself but NOT on the array inside the obj instance.
What I definitely can do and it works is set the obj.array[i][j] under the cell like this:
cell = path.back();
cell->state = State::visited;
obj.array[cell->row][cell->column].state = State::visited;
What I wanted to know is if there is a way (through pointers I presume) to make the obj.array Cell element know that it's being set by the cell->state = State::visited;

Adding objects to the boost::graph

I am trying to create a graph of objects which I need to traverse using some traversal algorithm. At this very moment I am stuck trying to create the graph using my custom objects. The way I am trying to accomplish it is as follows:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <iostream>
using namespace std;
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::directedS> CustomGraph;
typedef boost::graph_traits<CustomGraph>::vertex_descriptor CustomVertex;
class CustomVisitor:public boost::default_dfs_visitor
{
public:
void discover_vertex(CustomVertex v,const CustomGraph& taskGraph) const
{
cerr<<v<<endl;
return;
}
};
class CustomObject{
private:
int currentId;
public:
CustomObject(int id){
currentId = id;
}
};
int main()
{
CustomGraph customGraph;
CustomObject* obj0 = new CustomObject(0);
CustomObject* obj1 = new CustomObject(1);
CustomObject* obj2 = new CustomObject(2);
CustomObject* obj3 = new CustomObject(3);
typedef std::pair<CustomObject*,CustomObject*> Edge;
std::vector<Edge> edgeVec;
edgeVec.push_back(Edge(obj0,obj1));
edgeVec.push_back(Edge(obj0,obj2));
edgeVec.push_back(Edge(obj1,obj2));
edgeVec.push_back(Edge(obj1,obj3));
customGraph(edgeVec.begin(),edgeVec.end());
CustomVisitor vis;
boost::depth_first_search(customGraph,boost::visitor(vis));
return 0;
}
But this doesn't seem to be the right way to create objects within the vertices. Can somebody guide me as to what is the correct way to create nodes such that I can retrieve my objects while traversing the graph.
Thanks
Hi I know this is a rather old question, but there might others that can benefit from an answer.
It seems as if you have forgotten to define that your Graph will have a custom class as vertices. You have to add a fourth parameter to your typedef and add a typedef for your edge:
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::directedS, CustomObject> CustomGraph;
typedef boost::graph_traits<CustomGraph>::vertex_descriptor CustomVertex;
typedef boost::graph_traits<CustomGraph>::edge_descriptor CustomEdge;
Then I usually add my nodes before connecting them with edges:
// Create graph and custom obj's
CustomGraph customGraph
CustomObject obj0(0);
CustomObject obj1(1);
CustomObject obj2(2);
CustomObject obj3(3);
// Add custom obj's to the graph
// (Creating boost vertices)
CustomVertex v0 = boost::add_vertex(obj0, customGraph);
CustomVertex v1 = boost::add_vertex(obj1, customGraph);
CustomVertex v2 = boost::add_vertex(obj2, customGraph);
CustomVertex v3 = boost::add_vertex(obj3, customGraph);
// Add edge
CustomEdge edge;
bool edgeExists;
// check if edge allready exist (only if you don't want parallel edges)
boost::tie(edge, edgeExists) = boost::edge(v0 , v1, customGraph);
if(!edgeExists)
boost::add_edge(v0 , v1, customGraph);
// write graph to console
cout << "\n-- graphviz output START --" << endl;
boost::write_graphviz(cout, customGraph);
cout << "\n-- graphviz output END --" << endl;