座標変換自体は,ユーザーが注意してソースコード内に決め打ちをすれば問題なく行える.しかし,バグの温床となりやすい箇所である.逆行列にし忘れた場合や掛ける順番を間違えた場合などである.
コード内決め打ちと比較してパフォーマンスは低下するが座標系のつながりの検証もコーディングすることで,これらのバグを防止することができる.
今回は,Boost Graph Library (BGL)を用いて,より高度な座標系群の記述を試みる.
設計指針
サンプルソース
※matrix_type は
matrix_traits<matrix_type>::inverse(const matrix_type&)
matrix_traits<matrix_type>::multiple(const matrix_type&, const matrix_type&)
でアダプトする
※いくつかtypo入れてますよと.コピペだけじゃ動かない.まぁmatrix_type実装しないと動かないのだけど.
コード内決め打ちと比較してパフォーマンスは低下するが座標系のつながりの検証もコーディングすることで,これらのバグを防止することができる.
今回は,Boost Graph Library (BGL)を用いて,より高度な座標系群の記述を試みる.
設計指針
- 各座標系をnodeとする
- 双方向グラフとし,向きを定義する
- エッジには変換行列とその向きをプロパティとして与える
// definition of edge property
struct transformation_prop_t
{
typedef boost::edge_propoerty_tag kind;
};
// definition of transformation
template<class T>
struct transform
{
T matrix;
};
// definition of transformation direction
struct transformation_direction_prop_t
{
typedef boost::edge_property_tag kind;
};
// definition of coordinate_systems class (T = matrix_type)
template<typename T>
class coordinate_systems
{
public:
typedef T matrix_type;
typedef boost::property<boost::vertex_name_t, std::string> vertex_property_t;
typedef boost::property<transformation_t, transform<matrix_type>*,
boost::property<transform_direction_type, bool,
boost::property<boost::edge_weight_t, int>>> edge_property_t;
typedef boost::adjacency_list<boost::listS, boost::vecS,
boost::bidirectionalS, vertex_property_t, edge_property_t> map_type;
typedef typename map_type::vertex_descriptor coordinate_type;
protected:
map_type map;
// get matrix from edge
T get_transformation(typename map_type::edge_descriptor e)
{
std::cout << "From " << boost::get(boost::vertex_name, map)[e.m_source] << "\t" <<
"To " << boost::get(boost::vertex_name, map)[e.m_target] << std::endl;
// forward direction
if( boost::get(transform_direction_tag_type(), map)[e] )
{
return boost::get(transformation_t(), map)[e]->mat;
}
// inverse direction
else
{
return matrix_traits<matrix_type>::inverse(boost::get(transformation_t(), map)[e]->mat);
}
}
public:
coordinate_systems(){}
// add new coordinate system by name
coordinate_type add_coordinate(std::string name)
{
coordinate_type coordinate = add_vertex(map);
boost::get(boost::vertex_name, map)[coordinate] = name;
return coordinate;
}
// add new transformation between two coordinates
void add_transform(coordinate_type& from, coordinate_type& to, transform<matrix_type>* t)
{
map_type::edge_descriptor e, inv_e;
bool is_added;
// two edges are made for forward and inverse direction.
// both the edges have the same pointer of the transformation, but direction property (bool) is different.
// forward direction edge
boost::tie(e, is_added) = add_edge(from, to, map);
boost::get(transformation_t(), map)[e] = t;
boost::get(transform_direction_type(), map)[e] = true;
// inverse direction edge
boost::tie(inv_e, is_added) = add_edge(to, from, map);
boost::get(transformation_t(), map)[inv_e] = t;
boost::get(transform_direction_type(), map)[inv_e] = false;
}
// get matrix from a coordinate to another coordinate
T get_transform(coordinate_type& from, coordinate_type& to)
{
std::vector<coordinate_t> parent(boost::num_vertices(map));
boost::dijkstra_shortest_paths(map, from, boost::predecessor_map(&parent[0]));
matrix_type m;
if(parent[to] == to) return m;
std::deque<coordinate_type> route;
coordinate_type e = to;
coordinate_type s = parent[e];
while(e != from)
{
auto edge = boost::edge(s, e, map);
m = matrix_traits<matrix_t>::multiple(get_transformation(edge.first), m);
e = s;
s = parent[s];
}
return m;
}
};
サンプルソース
coordinate_systems<Matrix4x4> coords;
auto A_cs = coords.add_coordinate("A");
auto B_cs = coords.add_coordinate("B");
auto C_cs = coords.add_coordinate("C");
auto D_cs = coords.add_coordinate("D");
transform<Matrix4x4> A_T_B, A_T_C, B_T_D;
A_T_B.mat.TranslateLocal(10.0, 0.0, 0.0);
A_T_C.mat.TranslateLocal( 0.0, 10.0, 0.0);
B_T_D.mat.TranslateLocal( 0.0, 0.0, 10.0);
coords.add_transform(A_CS, B_CS, &A_T_B);
coords.add_transform(A_CS, C_CS, &A_T_C);
coords.add_transform(B_CS, D_CS, &B_T_D);
std::cout << coords.get_transform(D_cs, C_cs) << std::endl;
※matrix_type は
matrix_traits<matrix_type>::inverse(const matrix_type&)
matrix_traits<matrix_type>::multiple(const matrix_type&, const matrix_type&)
でアダプトする
※いくつかtypo入れてますよと.コピペだけじゃ動かない.まぁmatrix_type実装しないと動かないのだけど.

コメントをかく