Compile errors with boost::geometry::buffer - c++

I want to buffer a linestring and getting some compile errors with boost::geometry::buffer.
I have the code below:
// type definitions
using boost_point = boost::geometry::model::d2::point_xy<double>;
using boost_polygon = boost::geometry::model::polygon<boost_point>;
using boost_multipolygon = boost::geometry::model::multi_polygon<boost_polygon>;
// buffer configurations
const double buffer_distance = 0.5;
const int points_per_circle = 10;
boost::geometry::strategy::buffer::distance_symmetric<double> distance_strategy(buffer_distance);
boost::geometry::strategy::buffer::join_round join_strategy(points_per_circle);
boost::geometry::strategy::buffer::end_round end_strategy(points_per_circle);
boost::geometry::strategy::buffer::point_circle circle_strategy(points_per_circle);
boost::geometry::strategy::buffer::side_straight side_strategy;
// convert 3d polyline to 2d polyline then to boost linestring
std::vector<Eigen::Vector3d> polyline_3d = get_polyline_3d();
std::vector<boost_point> polyline_2d = polyline_3d |
ranges::view::transform([](const Eigen::Vector3d &point){return point.head<2>();}) |
ranges::view::transform([](const Eigen::Vector2d &point){return boost::geometry::make<boost_point>(point[0], point[1]);}) |
ranges::to<std::vector<boost_point>>();
auto ls = boost::geometry::model::linestring<boost_point>(polyline_2d.begin(),polyline_2d.end());
// get a buffered multipolygon from linestring
boost_multipolygon buffered;
boost::geometry::buffer(ls, buffered, distance_strategy, side_strategy, join_strategy, end_strategy, circle_strategy);
I'm getting the following compile errors:
boost/geometry/strategies/distance.hpp:97:5: error: no matching function for call to 'assertion_failed<false>(mpl_::failed************ (boost::geometry::strategy::distance::services::default_strategy<boost::geometry::point_tag, boost::geometry::segment_tag, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::cartesian_tag, boost::geometry::cartesian_tag, void>::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE_COMBINATION::************)(mpl_::assert_::types<boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::cartesian_tag, boost::geometry::cartesian_tag>))'
BOOST_MPL_ASSERT_MSG
boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp:71:13: error: no type named 'type' in 'struct boost::geometry::strategy::distance::services::default_strategy<boost::geometry::point_tag, boost::geometry::segment_tag, boost::geometry::model::d2::point_xy<double>, boost::geometry::model::d2::point_xy<double>, boost::geometry::cartesian_tag, boost::geometry::cartesian_tag, void>'
>::type ds_strategy_type;
^~~~~~~~~~~~~~~~
boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp:75:7: error: no type named 'type' in 'struct boost::geometry::strategy::distance::services::default_strategy<boost::geometry::point_tag, boost::geometry::segment_tag, boost::geometry::model::d2::point_xy<double>, boost::geometry::model::d2::point_xy<double>, boost::geometry::cartesian_tag, boost::geometry::cartesian_tag, void>'
> strategy_type;
^~~~~~~~~~~~~
boost/geometry/strategies/distance.hpp:97:5: error: no matching function for call to 'assertion_failed<false>(mpl_::failed************ (boost::geometry::strategy::distance::services::default_strategy<boost::geometry::point_tag, boost::geometry::segment_tag, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::cartesian_tag, boost::geometry::cartesian_tag, void>::NOT_IMPLEMENTED_FOR_THIS_POINT_TYPE_COMBINATION::************)(mpl_::assert_::types<boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::cartesian_tag, boost::geometry::cartesian_tag>))'
BOOST_MPL_ASSERT_MSG
boost/geometry/strategies/comparable_distance_result.hpp:51:8: error: no type named 'type' in 'struct boost::geometry::detail::distance::default_strategy<boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, boost::geometry::model::referring_segment<const boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian> >, boost::geometry::pointlike_tag, boost::geometry::segment_tag, false>'
boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp:884:48: error: no matching function for call to 'comparable_distance(boost::geometry::detail::buffer::buffered_piece_collection<boost::geometry::model::ring<boost::geometry::model::d2::point_xy<double>, true, true, std::vector, std::allocator>, boost::geometry::strategy::intersection::cartesian_segments<>, boost::geometry::detail::robust_policy<boost::geometry::model::d2::point_xy<double>, boost::geometry::model::point<long long int, 2, boost::geometry::cs::cartesian>, double> >::robust_point_type&, robust_segment_type&)'
I think my usage of buffer is pretty basic, and I'm confused why this would be causing so many compile errors. Am I missing something here?

I cannot reproduce this:
Live On Compiler Explorer
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/multi_polygon.hpp>
#include <range/v3/all.hpp>
#include <Eigen/Eigen>
namespace bg = boost::geometry;
// type definitions
using boost_point = bg::model::d2::point_xy<double>;
using boost_polygon = bg::model::polygon<boost_point>;
using boost_multipolygon = bg::model::multi_polygon<boost_polygon>;
std::vector<Eigen::Vector3d> get_polyline_3d() { return {}; }
int main()
{
using ranges::views::transform;
// convert 3d polyline to 2d polyline then to boost linestring
std::vector<Eigen::Vector3d> polyline_3d = get_polyline_3d();
std::vector<boost_point> polyline_2d =
polyline_3d //
| transform([](const Eigen::Vector3d& point) { return point.head<2>(); }) //
| transform([](const Eigen::Vector2d& point) { return bg::make<boost_point>(point[0], point[1]); }) //
| ranges::to<std::vector<boost_point>>();
auto ls = bg::model::linestring<boost_point>(polyline_2d.begin(),
polyline_2d.end());
// get a buffered multipolygon from linestring
boost_multipolygon buffered;
{
// buffer configurations
const double buffer_distance = 0.5;
const int points_per_circle = 10;
namespace bs = bg::strategy::buffer;
bs::distance_symmetric<double> distance_strategy(buffer_distance);
bs::join_round join_strategy(points_per_circle);
bs::end_round end_strategy(points_per_circle);
bs::point_circle circle_strategy(points_per_circle);
bs::side_straight side_strategy;
bg::buffer(ls, buffered, distance_strategy, side_strategy, join_strategy,
end_strategy, circle_strategy);
}
}
Which compiles fine for me on my GCC 10, Boost 1.78, Eigen 3.3.4, Rangev3 (0.11.0-44-g81b6d3f1b). Perhaps you were missing an include?

Related

Slicing Eigen tensor: Error accessing matrices from tensors

I am new to tensor in Eigen and just trying to run simple examples here. This is the code I have it's to access the first matrix in a tensor. Let's say I have a tensor with size ((nz+1),ny,nx), where each matrix in this tensor should have the shape or size of (nz+1)-by-ny. The thing is I can only extract a matrix that returns size ny-by-nz.
The code:
static const int nx = 10;
static const int ny = 10;
static const int nz = 10;
Eigen::Tensor<double, 3> epsilon((nz+1),ny,nx);
epsilon.setZero();
//slicing test: access first matrix in tensor
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {1,ny,nx}; //Finish point
std::array<long,2> shape2 = {(ny),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape2) << std::endl;
The answer is a matrix with a 10-by-10 size. How can I change this to extract slice and reshape it into a 11x10 matrix instead (11 rows and 10 columns). I tried changing last line to std::array<long,2> shape2 = {(nz+1),(nx)}; but this returns the error:
Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::TensorEvaluator(const XprType&, const Device&) [with NewDimensions = const std::array<long int, 2>; ArgType = Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> >; Device = Eigen::DefaultDevice; Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::XprType = Eigen::TensorReshapingOp<const std::array<long int, 2>, Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> > >]: Assertion `internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions())' failed.
Aborted
How can I change the number of rows in this matrix? Thanks
I was able to fix:
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {(nz+1),nx,1}; //Finish point:(row,column,matrix)
std::array<long,2> shape = {(nz+1),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape) << std::endl;

Initializing segments of an Eigen VectorXd

I'd like to efficiently initialize segments of an VectorXd object from the Eigen library. This vector is large (~1e6) so I would like to do this efficiently. Below is an example showing what I was thinking.
size_t N = 1e6;
std::vector<double> F(1., 2., 3., 4.);
Eigen::VectorXd ln_f_origin( F.size() * num_B );
for (size_t i=0; i<F.size(); i++) {
ln_f_origin.segment(i*num_B, num_B) = log(F[i]/num_B);
}
This doesn't seem to be working. I'm getting the following error:
error: no match for 'operator=' (operand types are 'Eigen::DenseBase<Eigen::Matrix<double, -1, 1> >::FixedSegmentReturnType<-1>::Type' {aka 'Eigen::VectorBlock<Eigen::Matrix<double, -1, 1>, -1>'} and 'double')

Eigen matrix ros/cols not working out right

I can't get this to compile:
Eigen::Map<Eigen::Matrix<const T, EA::ColsAtCompileTime, 1>> x(vec);
auto result = a_ * x - b_; // a(60r,1200c) * x(1200r,1c) - b(60r,1c)
The two errors (about 1000 lines each) eventually conclude that the * and - operators can't be "overloaded" (their term, not mine).
a_ is of this type: typedef Eigen::Map<Eigen::Matrix<double, ROWS, COLS>> EA;
b_ is of this type: typedef Eigen::Map<Eigen::Matrix<double, ROWS, 1>> EB;
T is the Ceres Solver Jet type. The errors seem to bespeak a column/row mismatch rather than a type problem. I could be wrong, though; the output is entirely too verbose. Did I misunderstand how the rows and columns work with Eigen matrix operators?
Update: I followed the "fatal-errors" suggestion:
In file included from /usr/include/eigen3/Eigen/Core:437:0,
from /usr/local/include/ceres/jet.h:165,
from /usr/local/include/ceres/internal/autodiff.h:145,
from /usr/local/include/ceres/autodiff_cost_function.h:132,
from /usr/local/include/ceres/ceres.h:37,
from /home/brannon/Workspace/Solver/music_solver.cpp:3:
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h: In instantiation of ‘class Eigen::PlainObjectBase<Eigen::Matrix<const double, 1200, 1, 0, 1200, 1> >’:
/usr/include/eigen3/Eigen/src/Core/Matrix.h:178:7: required from ‘class Eigen::Matrix<const double, 1200, 1, 0, 1200, 1>’
/usr/include/eigen3/Eigen/src/Core/Map.h:24:32: required from ‘struct Eigen::internal::traits<Eigen::Map<Eigen::Matrix<const double, 1200, 1, 0, 1200, 1>, 0, Eigen::Stride<0, 0> > >’
/usr/include/eigen3/Eigen/src/Core/util/ForwardDeclarations.h:32:54: required from ‘struct Eigen::internal::accessors_level<Eigen::Map<Eigen::Matrix<const double, 1200, 1, 0, 1200, 1>, 0, Eigen::Stride<0, 0> > >’
/usr/include/eigen3/Eigen/src/Core/util/ForwardDeclarations.h:113:75: required from ‘class Eigen::Map<Eigen::Matrix<const double, 1200, 1, 0, 1200, 1>, 0, Eigen::Stride<0, 0> >’
/home/brannon/Workspace/Solver/music_solver.cpp:18:72: required from ‘bool MusicCostFunctor<MATRIX_A, MATRIX_B>::operator()(const T*, T*) const [with T = double; MATRIX_A = Eigen::Map<Eigen::Matrix<double, 60, 1200, 0, 60, 1200>, 0, Eigen::Stride<0, 0> >; MATRIX_B = Eigen::Map<Eigen::Matrix<double, 60, 1, 0, 60, 1>, 0, Eigen::Stride<0, 0> >]’
/usr/local/include/ceres/internal/variadic_evaluate.h:175:19: required from ‘static bool ceres::internal::VariadicEvaluate<Functor, T, N0, 0, 0, 0, 0, 0, 0, 0, 0, 0>::Call(const Functor&, const T* const*, T*) [with Functor = MusicCostFunctor<Eigen::Map<Eigen::Matrix<double, 60, 1200, 0, 60, 1200>, 0, Eigen::Stride<0, 0> >, Eigen::Map<Eigen::Matrix<double, 60, 1, 0, 60, 1>, 0, Eigen::Stride<0, 0> > >; T = double; int N0 = 1200]’
/usr/local/include/ceres/autodiff_cost_function.h:208:17: required from ‘bool ceres::AutoDiffCostFunction<CostFunctor, kNumResiduals, N0, N1, N2, N3, N4, N5, N6, N7, N8, N9>::Evaluate(const double* const*, double*, double**) const [with CostFunctor = MusicCostFunctor<Eigen::Map<Eigen::Matrix<double, 60, 1200, 0, 60, 1200>, 0, Eigen::Stride<0, 0> >, Eigen::Map<Eigen::Matrix<double, 60, 1, 0, 60, 1>, 0, Eigen::Stride<0, 0> > >; int kNumResiduals = 1; int N0 = 1200; int N1 = 0; int N2 = 0; int N3 = 0; int N4 = 0; int N5 = 0; int N6 = 0; int N7 = 0; int N8 = 0; int N9 = 0]’
/home/brannon/Workspace/Solver/music_solver.cpp:115:1: required from here
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:585:27: error: ‘static Eigen::PlainObjectBase<Derived>::MapType Eigen::PlainObjectBase<Derived>::Map(Eigen::PlainObjectBase<Derived>::Scalar*) [with Derived = Eigen::Matrix<const double, 1200, 1, 0, 1200, 1>; Eigen::PlainObjectBase<Derived>::MapType = Eigen::Map<Eigen::Matrix<const double, 1200, 1, 0, 1200, 1>, 0, Eigen::Stride<0, 0> >; Eigen::PlainObjectBase<Derived>::Scalar = const double]’ cannot be overloaded
static inline MapType Map(Scalar* data)
^~~
You need to tell Eigen how to mix your scalar types through Eigen:: ScalarBinaryOpTraits. See similar questions with solutions there:
https://forum.kde.org/viewtopic.php?f=74&t=141467
Transform matrix of 3D positions with corresponding transformation matrix
After looking again at this example:
https://groups.google.com/d/msg/ceres-solver/7ZH21XX6HWU/Z3E-k2fbAwAJ
I realized that I put the const in the wrong spot. It's supposed to be Map<const... rather than <const T.

Converting Eigen 4x4 Matrix to QMatrix4x4

I've been converting RGBDSLAM to armhf (https://github.com/felixendres/rgbdslam_v2) and I've been encountering errors with this function:
template <typename T >
QMatrix4x4 eigenTF2QMatrix(const T& transf)
{
Eigen::Matrix<double, 4, 4, Eigen::RowMajor> m = transf.matrix();
//QMatrix4x4 qmat( static_cast<qreal*>( m.data() ) ); (original line)
QMatrix4x4 qmat( m.data() );
printQMatrix4x4("From Eigen::Transform", qmat);
return qmat;
}
The line:
QMatrix4x4 qmat( m.data() );
as well as the original:
QMatrix4x4 qmat( static_cast<qreal*>( m.data() ) );
Gives me the error:
error: invalid conversion from 'Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 1> >::Scalar* {aka double*}' to 'int' [-fpermissive]
How can I fix this function to work on arm?
You cannot cast a pointer and expect it to work. There is the cast method of Eigen, but it does not work with temporaries, so you will have to perform a copy:
using Eigen;
Matrix<qreal, 4, 4, RowMajor> mcopy = m.cast<qreal>();
QMatrix4x4 qmat(mcopy.data());

Copying from grid_graph to adjacency_list with boost::copy_graph

I'm using the boost graph library and trying to initalise a MutableGraph to start life as a grid.
Edges will be added and removed later in life, so I think adjacency_list<vecS,listS,undirectedS> is the right choice.
My reading about BGL indicated that the sensible way to initalise it with these edges would be to take advantage of boost::grid_graph by using
boost::copy_graph to copy from a boost::grid_graph that can make all the initial edges for me for free.
I thought that made sense - copy_graph copies from a model of VertexListGraph to a model of a MutableGraph, which is exactly what I have.
I initially tried using the 2-argument version of copy_graph, with the vague hope that something sensible would happen with the defaults for the rest. That turned out not to be the case, grid_graph (for reasons I couldn't quite figure out) doesn't seem to have a facility for using PropertyMaps with either edges or vertices, so the default vertex_copy and edge_copy failed (with a compiler error) copying the properties.
Since the 2-argument version clearly didn't seem appropriate I move on and tried to implement my own binary operator for copying vertices and edges. Even with a 'no-op' copy this doesn't work as well as I'd hope (i.e. it doesn't compile).
I've put together a minimum working example that illustrates the problem:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/copy.hpp>
struct Position {
int x, y;
};
struct VertexProperties {
Position pos;
};
typedef boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS,
VertexProperties> Graph;
struct MyCopy {
template <typename S, typename D>
void operator()(const S& /*src*/, D& /*dest*/) {
// Nothing for now, deduced types to try and just make it compile
// TODO: set values for pos to reflect position on grid.
}
};
int main() {
boost::array<std::size_t, 2> lengths = { { 3, 3 } };
boost::grid_graph<2> grid(lengths);
Graph graph;
MyCopy copier;
// Using 3-Arg version of copy_graph so we can specify a custom way of copying to create the properties
boost::copy_graph(grid,graph,boost::bgl_named_params<MyCopy,boost::vertex_copy_t,
boost::bgl_named_params<MyCopy,boost::edge_copy_t> >(copier));
}
This example doesn't compile:
g++ -Wextra -Wall -O2 -g -o copytest.o -c copytest.cc
In file included from /usr/include/boost/graph/grid_graph.hpp:24:0,
from copytest.cc:2:
/usr/include/boost/iterator/transform_iterator.hpp: In constructor ‘boost::transform_iterator<UnaryFunction, Iterator, Reference, Value>::transform_iterator() [with UnaryFunc = boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >, Iterator = boost::counting_iterator<unsigned int, boost::use_default, boost::use_default>, Reference = boost::use_default, Value = boost::use_default]’:
/usr/include/boost/graph/copy.hpp:115:55: instantiated from ‘static void boost::detail::copy_graph_impl<0>::apply(const Graph&, MutableGraph&, CopyVertex, CopyEdge, Orig2CopyVertexIndexMap, IndexMap) [with Graph = boost::grid_graph<2u>, MutableGraph = boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, VertexProperties>, CopyVertex = MyCopy, CopyEdge = MyCopy, IndexMap = boost::grid_graph_index_map<boost::grid_graph<2u>, boost::array<unsigned int, 2u>, unsigned int>, Orig2CopyVertexIndexMap = boost::iterator_property_map<__gnu_cxx::__normal_iterator<void**, std::vector<void*, std::allocator<void*> > >, boost::grid_graph_index_map<boost::grid_graph<2u>, boost::array<unsigned int, 2u>, unsigned int>, void*, void*&>]’
/usr/include/boost/graph/copy.hpp:327:5: instantiated from ‘void boost::copy_graph(const VertexListGraph&, MutableGraph&, const boost::bgl_named_params<P, T, R>&) [with VertexListGraph = boost::grid_graph<2u>, MutableGraph = boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, VertexProperties>, P = MyCopy, T = boost::vertex_copy_t, R = boost::bgl_named_params<MyCopy, boost::edge_copy_t>]’
/mnt/home/ajw/code/hpcwales/copytest.cc:31:66: instantiated from here
/usr/include/boost/iterator/transform_iterator.hpp:100:26: error: no matching function for call to ‘boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >::grid_graph_vertex_at()’
/usr/include/boost/graph/grid_graph.hpp:104:7: note: candidates are: boost::detail::grid_graph_vertex_at<Graph>::grid_graph_vertex_at(const Graph*) [with Graph = boost::grid_graph<2u>]
/usr/include/boost/graph/grid_graph.hpp:100:33: note: boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >::grid_graph_vertex_at(const boost::detail::grid_graph_vertex_at<boost::grid_graph<2u> >&)
My analysis of that error is that it seems to be trying to default construct part of the internals of grid_graph, which can't be default constructed, for some reason that isn't terribly clear to me.
(clang doesn't really tell me anything I can't see from g++ here).
Questions:
Is this the right way to go about initalising a mutable graph to start as a regular grid? I initially thought it was much easier than writing a function to do so myself, but now I'm not so sure!
Why is the default value of orig_to_copy and/or vertex_index not appropriate here? I'm assuming that those two are the cause of the error. (Which, if any, of those is actually causing the problem? I can't decipher what the root cause of the current error is).
What is the "correct" way of fixing this?
You are on the right track, but there are two things that need to be changed in your code. The first is that there is a special method of defining custom vertex properties. The second is that there is a different syntax (more preferred and probably the only one that is correct) for BGL named parameters.
On the first item, please refer to the section of the documentation titled Custom Vertex Properties. Essentially, in order to define a custom vertex property, you need to first define a "tag type" (a struct with a name ending in _t):
struct vertex_position_t {
typedef boost::vertex_property_tag kind;
};
Then you include the tag type somewhere in the boost::property template that defines internally-stored vertex properties:
typedef boost::property<boost::vertex_index_t, std::size_t,
boost::property<vertex_position_t, Position> > VertexProperties;
The above typedef defines two internally-stored properties: index and the custom "position".
On the second item, the preferred way to use named parameters is a "method chaining-like" syntax. For example, if a function accepts two named parameters, named_param1 and named_param2, there are two functions in the boost namespace named named_param1 and named_param2, respectfully. The boost::named_param1 function accepts the value for the named_param1 parameter and returns an object having a named_param2 method (similarly, the boost::named_param2 function accepts the value for the named_param2 parameter and returns an object having a named_param1 method). You call the method to set the value for that named parameter (which in turn returns another object having methods for other supported named parameters).
In order to pass values val1 and val2 for named parameters named_param1 and named_param2, you can either use:
boost::named_parameter1(val1).named_param2(val2)
or:
boost::named_parameter2(val2).named_param1(val1)
For reference, here is a complete program that copies a grid to an object of the Graph type:
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/grid_graph.hpp>
#include <boost/property_map/property_map.hpp>
struct vertex_position_t {
typedef boost::vertex_property_tag kind;
};
struct Position {
std::size_t x, y;
Position()
: x(0), y(0)
{
}
};
typedef boost::property<boost::vertex_index_t, std::size_t, boost::property<vertex_position_t, Position> > VertexProperties;
typedef boost::adjacency_list<boost::vecS, boost::listS, boost::undirectedS, VertexProperties> Graph;
typedef boost::graph_traits<Graph> GraphTraits;
namespace detail {
typedef boost::grid_graph<2> Grid;
typedef boost::graph_traits<Grid> GridTraits;
struct grid_to_graph_vertex_copier {
typedef boost::property_map< Grid, boost::vertex_index_t>::type grid_vertex_index_map;
typedef boost::property_map< ::Graph, boost::vertex_index_t>::type graph_vertex_index_map;
typedef boost::property_map< ::Graph, ::vertex_position_t>::type graph_vertex_position_map;
const Grid& grid;
grid_vertex_index_map grid_vertex_index;
graph_vertex_index_map graph_vertex_index;
graph_vertex_position_map graph_vertex_position;
grid_to_graph_vertex_copier(const Grid& grid_, Graph& graph)
: grid(grid_), grid_vertex_index(get(boost::vertex_index_t(), grid_)),
graph_vertex_index(get(boost::vertex_index_t(), graph)),
graph_vertex_position(get(::vertex_position_t(), graph))
{
}
private:
Position grid_vertex_index_to_position(std::size_t idx) const {
unsigned num_dims = grid.dimensions();
assert(grid.dimensions() == 2);
idx %= grid.length(0) * grid.length(1);
Position ret;
ret.x = idx % grid.length(0);
ret.y = idx / grid.length(0);
return ret;
}
public:
void operator()(GridTraits::vertex_descriptor grid_vertex, ::GraphTraits::vertex_descriptor graph_vertex) const {
std::size_t idx = get(grid_vertex_index, grid_vertex);
put(graph_vertex_index, graph_vertex, idx);
Position pos = grid_vertex_index_to_position(idx);
std::cout << "grid_vertex = " << idx << ", pos.x = " << pos.x << ", pos.y = " << pos.y << std::endl;
put(graph_vertex_position, graph_vertex, pos);
}
};
struct grid_to_graph_edge_copier {
void operator()(GridTraits::edge_descriptor grid_edge, ::GraphTraits::edge_descriptor graph_edge) const {
}
};
}
int main()
{
boost::array<std::size_t, 2> lengths = { { 3, 5 } };
detail::Grid grid(lengths);
Graph graph;
boost::copy_graph(grid, graph, boost::vertex_copy(detail::grid_to_graph_vertex_copier(grid, graph))
.edge_copy(detail::grid_to_graph_edge_copier()));
std::cout << std::endl;
boost::write_graphviz(std::cout, graph);
return EXIT_SUCCESS;
}
When I ran this, I received the following output:
grid_vertex = 0, pos.x = 0, pos.y = 0
grid_vertex = 1, pos.x = 1, pos.y = 0
grid_vertex = 2, pos.x = 2, pos.y = 0
grid_vertex = 3, pos.x = 0, pos.y = 1
grid_vertex = 4, pos.x = 1, pos.y = 1
grid_vertex = 5, pos.x = 2, pos.y = 1
grid_vertex = 6, pos.x = 0, pos.y = 2
grid_vertex = 7, pos.x = 1, pos.y = 2
grid_vertex = 8, pos.x = 2, pos.y = 2
grid_vertex = 9, pos.x = 0, pos.y = 3
grid_vertex = 10, pos.x = 1, pos.y = 3
grid_vertex = 11, pos.x = 2, pos.y = 3
grid_vertex = 12, pos.x = 0, pos.y = 4
grid_vertex = 13, pos.x = 1, pos.y = 4
grid_vertex = 14, pos.x = 2, pos.y = 4
graph G {
0;
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
12;
13;
14;
0--1 ;
1--2 ;
3--4 ;
4--5 ;
6--7 ;
7--8 ;
9--10 ;
10--11 ;
12--13 ;
13--14 ;
1--0 ;
2--1 ;
4--3 ;
5--4 ;
7--6 ;
8--7 ;
10--9 ;
11--10 ;
13--12 ;
14--13 ;
0--3 ;
1--4 ;
2--5 ;
3--6 ;
4--7 ;
5--8 ;
6--9 ;
7--10 ;
8--11 ;
9--12 ;
10--13 ;
11--14 ;
3--0 ;
4--1 ;
5--2 ;
6--3 ;
7--4 ;
8--5 ;
9--6 ;
10--7 ;
11--8 ;
12--9 ;
13--10 ;
14--11 ;
}