読者です 読者をやめる 読者になる 読者になる

ゆとりーなの日記

日記的な事を書いて行くと思はれる

とんちんかんなこと言ってたらどうしよう

 巷で話題のBoost.Geometry、Boost.Fusionと組み合わせられると聞いて試してみたのですが一つ気になることがあったので。
 とりあえずサンプルのコードを見て試してみたわけです。

#include <iostream>
#include <boost/fusion/include/adapt_struct_named.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/adapted/boost_fusion.hpp>

struct sample_point3d {
    double x;
    double y;
    double z;
};

BOOST_FUSION_ADAPT_STRUCT(sample_point3d, (double, x) (double, y) (double, z))
BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(sample_point3d)

int main() {
  sample_point3d a, b, c;
    
  boost::geometry::assign_values(a, 3, 2, 1);
    
  boost::fusion::at_c<0>(b) = 6;
  boost::fusion::at_c<1>(b) = 5;
  boost::fusion::at_c<2>(b) = 4;
    
  c.x = 9;
  c.y = 8;
  c.z = 7;
    
  std::cout << "Distance a-b: " << boost::geometry::distance(a, b) << std::endl;
  std::cout << "Distance a-c: " << boost::geometry::distance(a, c) << std::endl;

  return 0;
}

実行結果

Distance a-b: 5.19615
Distance a-c: 10.3923

 まぁ冷静に動きます。ここで二次元ポイントも一緒にやろうとして以下のコードを追加すると途端にコンパイルエラーになるのです。

struct sample_point2d {
    double x;
    double y;
};

BOOST_FUSION_ADAPT_STRUCT(sample_point2d, (double, x) (double, y))
BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(sample_point2d)

エラー内容の抜粋

'boost::geometry::traits::coordinate_system<Sequence,boost::enable_if<boost::geometry::fusion_adapt_detail::is_fusion_sequence<Sequence>>::type>' : クラス テンプレートは既に定義されています

 要するにfusion向けのgeometryの特殊化が被ってると怒られるわけです。というわけでBOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(sample_point2d)を削除してやればコンパイルが通るようになります。

#include <iostream>
#include <boost/fusion/include/adapt_struct_named.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/adapted/boost_fusion.hpp>

struct sample_point3d {
    double x;
    double y;
    double z;
};

BOOST_FUSION_ADAPT_STRUCT(sample_point3d, (double, x) (double, y) (double, z))
BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(sample_point3d)

struct sample_point2d {
    double x;
    double y;
};

BOOST_FUSION_ADAPT_STRUCT(sample_point2d, (double, x) (double, y))

int main() {
  {
  sample_point3d a, b, c;
    
  boost::geometry::assign_values(a, 3, 2, 1);
    
  boost::fusion::at_c<0>(b) = 6;
  boost::fusion::at_c<1>(b) = 5;
  boost::fusion::at_c<2>(b) = 4;
    
  c.x = 9;
  c.y = 8;
  c.z = 7;
    
  std::cout << "Distance a-b: " << boost::geometry::distance(a, b) << std::endl;
  std::cout << "Distance a-c: " << boost::geometry::distance(a, c) << std::endl;
  }

  {
  sample_point2d a, b, c;
    
  boost::geometry::assign_values(a, 3, 2);
    
  boost::fusion::at_c<0>(b) = 6;
  boost::fusion::at_c<1>(b) = 5;
    
  c.x = 9;
  c.y = 8;
    
  std::cout << "Distance a-b: " << boost::geometry::distance(a, b) << std::endl;
  std::cout << "Distance a-c: " << boost::geometry::distance(a, c) << std::endl;
  }

  return 0;
}

実行結果

Distance a-b: 5.19615
Distance a-c: 10.3923
Distance a-b: 4.24264
Distance a-c: 8.48528

 詰まりBOOST_GEOMETRY_REGISTER_BOOST_FUSION_CSはどこかに一つだけあればいいことになります。これは少し分かりにくい気がするのです。実際BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CSの実装を見ても、引数はどこにも使われていないみたいなのでfusionをgeometryで使いたい場合はBOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS()をどこか一箇所で定義しておくとした方が分かりやすい気がします。
 ついでに言えば、BOOST_GEOMETRY_REGISTER_BOOST_ARRAY_CSの場合は引数にCoordinateSystemを渡すようになっており、

BOOST_GEOMETRY_REGISTER_BOOST_ARRAY_CS(cs::cartesian)

みたいな感じに使うようになっています。BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CSも引数名は同じですし、ひょっとすると

BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(cs::cartesian)

のように使うのが正解なのではないかという気もします(サンプルのミス?)。とすると実装の方もtagにcs::cartesianを決め打ちしてしているのもミスで、本来は引数のCoordinateSystemを使うようにしたかったのではないかと説もあります。
 実際のところはどうなんでしょうか。
追記:
 やはりどうもバグだったようです。

BOOST_GEOMETRY_REGISTER_BOOST_FUSION_CS(cs::cartesian)

のように使うのが正しいみたいです。現状ではtagがcs::cartesianで決め打ちなので他のCoordinate Systemsを指定しても意味なくなってしまいますが恐らくそのうちに修正が入るのではと思います。