Boost图形可视化库读取所有属性

3
当加载 .dot 文件时,我希望在不事先定义属性的情况下读取所有属性。 在下面的代码片段中,我不想指定例如读取 weight。其他数据集具有其他属性,我不想将它们作为变量添加到结构中。
boost::dynamic_properties dp;
dp.property( "node_id", get( &Vertex::name, _graph.m_graph ) );
//dp.property("weight", get(&Edge::weight, _graph.m_graph));
boost::read_graphviz( file, _graph.m_graph, dp );

我发现另一个答案做了类似的事情,但是对于我的情况,我无法让它工作。在我的数据集中,属性位于边缘上,它们是像[weight=1]这样的数字。我尝试编辑这一行:return boost::make_shared<dynamic_property_map_impl<unsigned int, std::string>>();使用不同的模板类型,但我只得到了node_id:

return boost::make_shared<dynamic_property_map_impl<std::string, std::string>>();
return boost::make_shared<dynamic_property_map_impl<std::string, float>>();

完整的代码片段如下:

#include <boost/graph/graphviz.hpp>
#include <boost/program_options.hpp>
#include <boost/exception/exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include "read_graphviz_new.cpp"

template<typename TKey, typename TValue>
class dynamic_property_map_impl : public boost::dynamic_property_map {
    std::map<TKey, TValue>  m_map;

public:
    boost::any get(const boost::any& key) override { return m_map[boost::any_cast<TKey>(key)]; }
    std::string get_string(const boost::any& key) override { std::ostringstream s; s << m_map[boost::any_cast<TKey>(key)]; return s.str(); }
    void put(const boost::any& key, const boost::any& value) override { m_map[boost::any_cast<TKey>(key)] = boost::any_cast<TValue>(value); }
    const std::type_info& key() const override { return typeid(TKey); }
    const std::type_info& value() const override { return typeid(TValue); }
};

boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(const std::string&,
    const boost::any&,
    const boost::any&) {

    return boost::make_shared<dynamic_property_map_impl<unsigned int, std::string>>();
}

struct Vertex
{
    std::string name;
};

struct Edge
{
    float weight = 1.f;
};

typedef boost::property<boost::graph_name_t, std::string> graph_p;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge, graph_p> graph_u;

void Graph::Load(std::string filepath) {
    std::ifstream file(filepath);
    graph_u graph;

    try {
        boost::dynamic_properties dp(handle_custom_properties);
        dp.property("node_id", get(&Vertex::name, graph));
        //dp.property("weight", get(&Edge::weight, graph));
        boost::read_graphviz(file, graph, dp);
    }
    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    catch (boost::exception& e) {
        std::cerr << boost::diagnostic_information(e) << std::endl;
    }
}

我的数据集如下所示:

strict graph  {
1;
2;
3;
...
1 -- 2  [weight=1];
2 -- 3  [weight=8];
...
}
1个回答

3

我之前写过类似的答案:

对于你自己的动态属性映射子类,恭喜你能够做到这一步。这也是一个不错的方法。

你的问题是unsigned int仅为顶点描述符硬编码(边描述符不兼容)。同样地,std::string硬编码为字符串值。您需要使它们都具有灵活性:

boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(std::string const&, boost::any const& k, boost::any const& v) {
    using V = graph_u::vertex_descriptor;
    using E = graph_u::edge_descriptor;

    if (k.type() == typeid(V)) {
        if (v.type() == typeid(std::string))
            return boost::make_shared<dynamic_property_map_impl<V, std::string>>();
        if (v.type() == typeid(double))
            return boost::make_shared<dynamic_property_map_impl<V, double>>();
    } else if (k.type() == typeid(E)) {
        if (v.type() == typeid(std::string))
            return boost::make_shared<dynamic_property_map_impl<E, std::string>>();
        if (v.type() == typeid(double))
            return boost::make_shared<dynamic_property_map_impl<E, double>>();
    }
    throw std::runtime_error("Unsupported " + boost::core::demangle(v.type().name()));
}

这将能够工作:

在 Coliru 上实时运行

#include <boost/exception/diagnostic_information.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/lexical_cast.hpp>

template <typename TKey, typename TValue>
class dynamic_property_map_impl : public boost::dynamic_property_map {
    std::map<TKey, TValue> m_map;

    using any = boost::any;
    TValue& lookup(TKey const& key) { return m_map[key];                  } 
    TValue& lookup(any const& key)  { return lookup(any_cast<TKey>(key)); } 

  public:
    any get(any const& key) override                    { return lookup(key);                                   } 
    std::string get_string(any const& key) override     { return boost::lexical_cast<std::string>(lookup(key)); } 
    void put(any const& key, any const& value) override { lookup(key) = any_cast<TValue>(value);                } 

    std::type_info const& key()   const override { return typeid(TKey);   } 
    std::type_info const& value() const override { return typeid(TValue); } 
};

struct Vertex { std::string id; };
struct Edge {};

using graph_p = boost::property<boost::graph_name_t, std::string>;
using graph_u = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge, graph_p>;

boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(std::string const&, boost::any const& k, boost::any const& v) {
    using V = graph_u::vertex_descriptor;
    using E = graph_u::edge_descriptor;

    if (k.type() == typeid(V)) {
        if (v.type() == typeid(std::string))
            return boost::make_shared<dynamic_property_map_impl<V, std::string>>();
        if (v.type() == typeid(double))
            return boost::make_shared<dynamic_property_map_impl<V, double>>();
    } else if (k.type() == typeid(E)) {
        if (v.type() == typeid(std::string))
            return boost::make_shared<dynamic_property_map_impl<E, std::string>>();
        if (v.type() == typeid(double))
            return boost::make_shared<dynamic_property_map_impl<E, double>>();
    }
    throw std::runtime_error("Unsupported " + boost::core::demangle(v.type().name()));
}

int main() try {
    graph_u g;

    boost::dynamic_properties dp(handle_custom_properties);
    dp.property("node_id", get(&Vertex::id, g));

    {
        std::istringstream file(R"(strict graph  {
            1;
            2;
            3;
            1 -- 2  [weight=1];
            2 -- 3  [weight=8];
            })");

        read_graphviz(file, g, dp);
    }

    write_graphviz_dp(std::cout, g, dp);
} catch (boost::exception const& e) {
    std::cerr << diagnostic_information(e) << std::endl;
} catch (std::exception const& e) {
    std::cerr << e.what() << std::endl;
}

打印

graph G {
1;
2;
3;
1--2  [weight=1];
2--3  [weight=8];
}

Coliru 似乎暂时无法使用。稍后再试。 - sehe
而 Coliru 已经回来了。 - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接