Cyantttt
Cyantttt

Reputation: 13

C++ Boost kamada_kawai_spring_layout Problem

To achieve a planar embedding with fixed positions for some vertices,

  1. I am currently using the force-directed layout method. Is this approach feasible?
  2. I am currently facing an issue with compiling the kamada_kawai_spring_layout from the Boost library.
typedef geometry::model::point<double, 2, geometry::cs::cartesian> point ;
typedef boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS,
boost::property<boost::vertex_index_t, int>,
boost::property<boost::edge_index_t, int,
boost::property<boost::edge_weight_t, int> >
graph;
graph g(this->HubSet.size());

//Add edge
map<pairs,int>::iterator iter;
for(iter = this->edge.begin() ; iter != this->edge.end() ; iter++)
{
   pairs tmpPair = iter->first;
   add_edge(tmpPair.first, tmpPair.second, 1.0, g);
}

//Position Map
typedef vector<point> PositionMap;
PositionMap position(num_vertices(g));
position[33] = point(250.0, 2000.0);
position[35] = point(8000.0, 2000.0);
auto position_map = boost::make_iterator_property_map(position.begin(), get(boost::vertex_index, g));

//Topology
std::minstd_rand gen;
rectangle_topology<std::minstd_rand> topo(gen, 0.0, 0.0, 9000.0, 9000.0);
random_graph_layout(g, position_map, topo);

//Call Force directed algorithm
boost::kamada_kawai_spring_layout(g,
                                  position_map,
                                  get(edge_weight, g),
                                  topo,
                                  edge_length(100.0) );

I would like to inquire about an issue with my code compilation. Could you please help me identify the modifications needed for successful compilation?

Upvotes: 1

Views: 117

Answers (1)

sehe
sehe

Reputation: 393664

It’s impossible to figure out what error you are getting, because you post incomplete code.

If I make up some of the missing code my best guess is that your position map fails to match the documented criteria:

The type PositionMap must be a model of Writable Property Map, with the graph's vertex descriptor type as its key type and Topology::point_type as its value type.

So, instead use:

using Topology = boost::rectangle_topology<std::minstd_rand>;
using Point    = Topology::point_type;

Then, when we also make the edge weight arithmetically compatible with the coordinate types, this has the potential to compile:

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/kamada_kawai_spring_layout.hpp>
#include <boost/graph/random_layout.hpp>
#include <random>

using Topology = boost::rectangle_topology<std::minstd_rand>;
using Point    = Topology::point_type;
using Graph    = boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,              //
                                    boost::property<boost::vertex_index_t, int>,                  //
                                    boost::property<boost::edge_index_t, int,                     //
                                                    boost::property<boost::edge_weight_t, double> //
                                                    >>;
struct Program {
    std::vector<int> HubSet;
    using pairs = std::pair<size_t, size_t>;
    std::map<pairs, int> edge;

    Program()
        : HubSet(42) // no clue, just made it big enough for position[35] to be a valid index
    {}

    void foo() {
        Graph g(this->HubSet.size());

        // Add edge
        std::map<pairs, int>::iterator iter;
        for (iter = this->edge.begin(); iter != this->edge.end(); iter++) {
            pairs tmpPair = iter->first;
            add_edge(tmpPair.first, tmpPair.second, 1.0, g);
        }

        // Position Map
        using PositionMap = std::vector<Point>;
        PositionMap position(num_vertices(g));

        auto make_point = [](double x, double y) {
            Point p;
            p[0] = x;
            p[1] = y;
            return p;
        };
        position[33] = make_point(250.0, 2000.0);
        position[35] = make_point(8000.0, 2000.0);
        auto position_map = boost::make_iterator_property_map(position.begin(), get(boost::vertex_index, g));

        // Topology
        std::minstd_rand gen;
        Topology         topo(gen, 0.0, 0.0, 9000.0, 9000.0);
        random_graph_layout(g, position_map, topo);

        // Call Force directed algorithm
        boost::kamada_kawai_spring_layout(g, position_map, get(boost::edge_weight, g), topo,
                                          boost::edge_length(100.0));
    }
};

int main() {
    Program p;
    p.foo();
}

BONUS

If you MUST have geometry support down the road, you can adapt the point type:

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/register/point.hpp>

namespace bg = boost::geometry;
using Point  = Topology::point_type;

namespace boost::geometry::traits {
    template<> struct tag<Point>               { using type = point_tag;         };
    template<> struct coordinate_type<Point>   { using type = double;            };
    template<> struct coordinate_system<Point> { using type = bg::cs::cartesian; };
    template<> struct dimension<Point> : std::integral_constant<std::size_t, 2> {};
    template<> struct access<Point, 0> {
        static inline double get(Point const& p) { return p[0]; }
        static inline void   set(Point& p, double const& value) { p[0] = value; }
    };
    template <> struct access<Point, 1> {
        static inline double get(Point const& p) { return p[1]; }
        static inline void   set(Point& p, double const& value) { p[1] = value; }
    };
} // namespace boost::geometry::traits

At that point you can use boost::geometry::make<Point>(x,y) instead of the bespoke lambda.

Upvotes: 0

Related Questions