Boost::Graph:如何使用自定义顶点导入 graphviz class
Boost::Graph: how to import graphviz with custom Vertex class
我有这个 graphviz 输入:
graph G {
0[p="(30, 3, 2)"];
1[p="(29, 3, 2)"];
2[p="(30, 2, 2)"];
3[p="(30, 3, 3)"];
4[p="(30, 2, 3)"];
5[p="(29, 3, 3)"];
6[p="(29, 2, 3)"];
0--1;
2--0;
3--4;
5--3;
6--5;
5--1;
3--0;
4--6;
2--4;
}
类型有:
struct Vertex
{
glm::vec3 p = {};
// ...
};
typedef
boost::adjacency_list<
boost::setS,
boost::vecS,
boost::undirectedS,
Vertex,
Edge>
Graph;
如何使用 boost::read_graphviz
并将其设置为正确地将 graphviz 中的 p
属性 适配到结构 Vertex
的 p
字段?我尝试将 boost::dynamic_properties
与 dp.property("p", boost::get(&Vertex::p, g));
一起使用,但它不起作用,因为类型不匹配(也许是因为是 write_graphviz
)。
是的,你要求英雄气概。 dynamic_properties
工具实际上假设您将访问对象中的左值属性,而不是转换后的值。
我以前 运行 参与过这个:
- boost::dynamic_properties and immutable graph object
- 您可以通过搜索找到更多景点 my answers for
dynamic_properties
解决它
该库是完全通用的。 属性 映射是高度通用的并且不假定左值,这可以从 concept hierarchy that distinguishes between ReadWritePropertyMap
and LvaluePropertyMap
.
中看出
因此您实际上可以“只”编写自己的 属性 地图适配器:
namespace Adapt {
template <typename Prop> struct Vec3 {
Prop inner;
Vec3(Prop map) : inner(map) { }
// traits
using value_type = std::string;
using reference = std::string;
using key_type = typename boost::property_traits<Prop>::key_type;
using category = boost::read_write_property_map_tag;
friend std::string get(Vec3 adapt, key_type const& key);
friend void put(Vec3 adapt, key_type const& key, value_type const& value);
};
}
我将根据您预期的文本序列化格式快速填写 get
和 put
的一些合理实施。具体的我就不解释了,大家可以按照自己认为合适的方式来写:
friend std::string get(Vec3 adapt, key_type const& key) {
auto const& v = get(adapt.inner, key);
std::ostringstream oss;
oss << "(" << v.x << "," << v.y << "," << v.z << ")";
return oss.str();
}
friend void put(Vec3 adapt, key_type const& key, std::string const& value) {
using namespace boost::spirit::x3;
float x,y,z;
auto attr = std::tie(x,y,z);
phrase_parse( //
begin(value), end(value),
'(' > double_ > ',' > double_ > ',' > double_ > ')' > eoi,
space, attr);
put(adapt.inner, key, glm::vec3{x,y,z});
}
完整演示
现在您可以使用改编的属性地图:
Graph g;
auto id = boost::get(&Vertex::id, g);
auto p = Adapt::Vec3{boost::get(&Vertex::p, g)};
boost::dynamic_properties dp;
dp.property("node_id", id);
dp.property("p", p);
如果我们往返图形:
{
std::ifstream ifs("input.txt", std::ios::binary);
boost::read_graphviz(ifs, g, dp);
}
boost::write_graphviz_dp(std::cout, g, dp);
我们可以看到输入被保留了。遗憾的是,在撰写本文时,没有在线编译器可以同时支持 Boost 和 GLM,因此您必须自己 运行 该示例(参见 https://godbolt.org/z/xMKhz9G8e, https://wandbox.org/permlink/RkulvhWxcRnl1RbC 等)。
为此目的的完整列表:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <glm/glm.hpp>
#include <iostream>
#include <iomanip>
struct Vertex {
glm::vec3 p = {};
int id;
};
struct Edge { };
using Graph = boost::adjacency_list<boost::setS, boost::vecS,
boost::undirectedS, Vertex, Edge>;
using VD = Graph::vertex_descriptor;
using ED = Graph::edge_descriptor;
namespace Adapt {
template <typename Prop> struct Vec3 {
Prop inner;
Vec3(Prop map) : inner(map) { }
// traits
using value_type = std::string;
using reference = std::string;
using key_type = typename boost::property_traits<Prop>::key_type;
using category = boost::read_write_property_map_tag;
friend std::string get(Vec3 adapt, key_type const& key) {
auto const& v = get(adapt.inner, key);
std::ostringstream oss;
oss << "(" << v.x << "," << v.y << "," << v.z << ")";
return oss.str();
}
friend void put(Vec3 adapt, key_type const& key, std::string const& value) {
using namespace boost::spirit::x3;
float x,y,z;
auto attr = std::tie(x,y,z);
phrase_parse( //
begin(value), end(value),
'(' > double_ > ',' > double_ > ',' > double_ > ')' > eoi,
space, attr);
put(adapt.inner, key, glm::vec3{x,y,z});
}
};
}
int main()
{
Graph g;
auto id = boost::get(&Vertex::id, g);
auto p = Adapt::Vec3{boost::get(&Vertex::p, g)};
boost::dynamic_properties dp;
dp.property("node_id", id);
dp.property("p", p);
{
std::istringstream iss(R"~(
graph G {
0[p="(30, 3, 2)"]; 1[p="(29, 3, 2)"]; 2[p="(30, 2, 2)"]; 3[p="(30, 3, 3)"];
4[p="(30, 2, 3)"]; 5[p="(29, 3, 3)"]; 6[p="(29, 2, 3)"];
0--1; 2--0; 3--4; 5--3; 6--5; 5--1; 3--0; 4--6; 2--4; })~");
boost::read_graphviz(iss, g, dp);
}
boost::write_graphviz_dp(std::cout, g, dp);
}
版画
graph G {
0 [p="(30,3,2)"];
1 [p="(29,3,2)"];
2 [p="(30,2,2)"];
3 [p="(30,3,3)"];
4 [p="(30,2,3)"];
5 [p="(29,3,3)"];
6 [p="(29,2,3)"];
0--1 ;
2--0 ;
3--4 ;
5--3 ;
6--5 ;
5--1 ;
3--0 ;
4--6 ;
2--4 ;
}
我有这个 graphviz 输入:
graph G {
0[p="(30, 3, 2)"];
1[p="(29, 3, 2)"];
2[p="(30, 2, 2)"];
3[p="(30, 3, 3)"];
4[p="(30, 2, 3)"];
5[p="(29, 3, 3)"];
6[p="(29, 2, 3)"];
0--1;
2--0;
3--4;
5--3;
6--5;
5--1;
3--0;
4--6;
2--4;
}
类型有:
struct Vertex
{
glm::vec3 p = {};
// ...
};
typedef
boost::adjacency_list<
boost::setS,
boost::vecS,
boost::undirectedS,
Vertex,
Edge>
Graph;
如何使用 boost::read_graphviz
并将其设置为正确地将 graphviz 中的 p
属性 适配到结构 Vertex
的 p
字段?我尝试将 boost::dynamic_properties
与 dp.property("p", boost::get(&Vertex::p, g));
一起使用,但它不起作用,因为类型不匹配(也许是因为是 write_graphviz
)。
是的,你要求英雄气概。 dynamic_properties
工具实际上假设您将访问对象中的左值属性,而不是转换后的值。
我以前 运行 参与过这个:
- boost::dynamic_properties and immutable graph object
- 您可以通过搜索找到更多景点 my answers for
dynamic_properties
解决它
该库是完全通用的。 属性 映射是高度通用的并且不假定左值,这可以从 concept hierarchy that distinguishes between ReadWritePropertyMap
and LvaluePropertyMap
.
因此您实际上可以“只”编写自己的 属性 地图适配器:
namespace Adapt {
template <typename Prop> struct Vec3 {
Prop inner;
Vec3(Prop map) : inner(map) { }
// traits
using value_type = std::string;
using reference = std::string;
using key_type = typename boost::property_traits<Prop>::key_type;
using category = boost::read_write_property_map_tag;
friend std::string get(Vec3 adapt, key_type const& key);
friend void put(Vec3 adapt, key_type const& key, value_type const& value);
};
}
我将根据您预期的文本序列化格式快速填写 get
和 put
的一些合理实施。具体的我就不解释了,大家可以按照自己认为合适的方式来写:
friend std::string get(Vec3 adapt, key_type const& key) {
auto const& v = get(adapt.inner, key);
std::ostringstream oss;
oss << "(" << v.x << "," << v.y << "," << v.z << ")";
return oss.str();
}
friend void put(Vec3 adapt, key_type const& key, std::string const& value) {
using namespace boost::spirit::x3;
float x,y,z;
auto attr = std::tie(x,y,z);
phrase_parse( //
begin(value), end(value),
'(' > double_ > ',' > double_ > ',' > double_ > ')' > eoi,
space, attr);
put(adapt.inner, key, glm::vec3{x,y,z});
}
完整演示
现在您可以使用改编的属性地图:
Graph g;
auto id = boost::get(&Vertex::id, g);
auto p = Adapt::Vec3{boost::get(&Vertex::p, g)};
boost::dynamic_properties dp;
dp.property("node_id", id);
dp.property("p", p);
如果我们往返图形:
{
std::ifstream ifs("input.txt", std::ios::binary);
boost::read_graphviz(ifs, g, dp);
}
boost::write_graphviz_dp(std::cout, g, dp);
我们可以看到输入被保留了。遗憾的是,在撰写本文时,没有在线编译器可以同时支持 Boost 和 GLM,因此您必须自己 运行 该示例(参见 https://godbolt.org/z/xMKhz9G8e, https://wandbox.org/permlink/RkulvhWxcRnl1RbC 等)。
为此目的的完整列表:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <glm/glm.hpp>
#include <iostream>
#include <iomanip>
struct Vertex {
glm::vec3 p = {};
int id;
};
struct Edge { };
using Graph = boost::adjacency_list<boost::setS, boost::vecS,
boost::undirectedS, Vertex, Edge>;
using VD = Graph::vertex_descriptor;
using ED = Graph::edge_descriptor;
namespace Adapt {
template <typename Prop> struct Vec3 {
Prop inner;
Vec3(Prop map) : inner(map) { }
// traits
using value_type = std::string;
using reference = std::string;
using key_type = typename boost::property_traits<Prop>::key_type;
using category = boost::read_write_property_map_tag;
friend std::string get(Vec3 adapt, key_type const& key) {
auto const& v = get(adapt.inner, key);
std::ostringstream oss;
oss << "(" << v.x << "," << v.y << "," << v.z << ")";
return oss.str();
}
friend void put(Vec3 adapt, key_type const& key, std::string const& value) {
using namespace boost::spirit::x3;
float x,y,z;
auto attr = std::tie(x,y,z);
phrase_parse( //
begin(value), end(value),
'(' > double_ > ',' > double_ > ',' > double_ > ')' > eoi,
space, attr);
put(adapt.inner, key, glm::vec3{x,y,z});
}
};
}
int main()
{
Graph g;
auto id = boost::get(&Vertex::id, g);
auto p = Adapt::Vec3{boost::get(&Vertex::p, g)};
boost::dynamic_properties dp;
dp.property("node_id", id);
dp.property("p", p);
{
std::istringstream iss(R"~(
graph G {
0[p="(30, 3, 2)"]; 1[p="(29, 3, 2)"]; 2[p="(30, 2, 2)"]; 3[p="(30, 3, 3)"];
4[p="(30, 2, 3)"]; 5[p="(29, 3, 3)"]; 6[p="(29, 2, 3)"];
0--1; 2--0; 3--4; 5--3; 6--5; 5--1; 3--0; 4--6; 2--4; })~");
boost::read_graphviz(iss, g, dp);
}
boost::write_graphviz_dp(std::cout, g, dp);
}
版画
graph G {
0 [p="(30,3,2)"];
1 [p="(29,3,2)"];
2 [p="(30,2,2)"];
3 [p="(30,3,3)"];
4 [p="(30,2,3)"];
5 [p="(29,3,3)"];
6 [p="(29,2,3)"];
0--1 ;
2--0 ;
3--4 ;
5--3 ;
6--5 ;
5--1 ;
3--0 ;
4--6 ;
2--4 ;
}