| 1 |
/*! |
| 2 |
\file |
| 3 |
\brief 座標系の操作 |
| 4 |
|
| 5 |
\author Satofumi KAMIMURA |
| 6 |
|
| 7 |
$Id$ |
| 8 |
*/ |
| 9 |
|
| 10 |
#include "CoordinateCtrl.h" |
| 11 |
#include "MathUtils.h" |
| 12 |
#include <set> |
| 13 |
#include <cstddef> |
| 14 |
|
| 15 |
using namespace beego; |
| 16 |
|
| 17 |
|
| 18 |
/*! |
| 19 |
\brief CoordinateCtrl の内部クラス |
| 20 |
*/ |
| 21 |
struct CoordinateCtrl::pImpl { |
| 22 |
typedef std::set<const CoordinateCtrl*> CrdSet; |
| 23 |
static CrdSet crd_set; |
| 24 |
|
| 25 |
const CoordinateCtrl* parent; //!< 親座標系へのポインタ |
| 26 |
Position<int> offset; //!< 親座標系で自座標系の原点位置 |
| 27 |
|
| 28 |
pImpl(void) : parent(NULL) { |
| 29 |
} |
| 30 |
|
| 31 |
void convert(Position<int>& dst, const Position<int>& src, |
| 32 |
const Position<int>& offset) { |
| 33 |
|
| 34 |
double radian = offset.angle.to_rad(); |
| 35 |
int x = static_cast<int>(src.x * cos(radian) - src.y * sin(radian)); |
| 36 |
int y = static_cast<int>(src.x * sin(radian) + src.y * cos(radian)); |
| 37 |
dst.x = x + offset.x; |
| 38 |
dst.y = y + offset.y; |
| 39 |
dst.angle = rad(src.angle.to_rad() + offset.angle.to_rad()); |
| 40 |
} |
| 41 |
}; |
| 42 |
CoordinateCtrl::pImpl::CrdSet CoordinateCtrl::pImpl::crd_set; |
| 43 |
|
| 44 |
|
| 45 |
CoordinateCtrl::CoordinateCtrl(void) : pimpl(new pImpl) { |
| 46 |
pImpl::crd_set.insert(this); |
| 47 |
} |
| 48 |
|
| 49 |
|
| 50 |
CoordinateCtrl::~CoordinateCtrl(void) { |
| 51 |
pImpl::CrdSet::iterator it = pImpl::crd_set.find(this); |
| 52 |
if (it != pImpl::crd_set.end()) { |
| 53 |
pImpl::crd_set.erase(it); |
| 54 |
} |
| 55 |
} |
| 56 |
|
| 57 |
|
| 58 |
bool CoordinateCtrl::isActive(const CoordinateCtrl* crd) { |
| 59 |
pImpl::CrdSet::iterator it = pImpl::crd_set.find(crd); |
| 60 |
if (it != pImpl::crd_set.end()) { |
| 61 |
return true; |
| 62 |
} else { |
| 63 |
return false; |
| 64 |
} |
| 65 |
} |
| 66 |
|
| 67 |
|
| 68 |
CoordinateCtrl* CoordinateCtrl::getParent(void) { |
| 69 |
return const_cast<CoordinateCtrl*>(pimpl->parent); |
| 70 |
} |
| 71 |
|
| 72 |
|
| 73 |
// 座標系をある座標系上に固定 |
| 74 |
// !!! 固定されてない座標系の関係もある、ってことな。そのときが NULL かと |
| 75 |
void CoordinateCtrl::setOrigin(const CoordinateCtrl* parent, |
| 76 |
int x, int y, Angle angle) { |
| 77 |
pimpl->parent = parent; |
| 78 |
set_Position(&pimpl->offset, x, y, angle); |
| 79 |
} |
| 80 |
|
| 81 |
|
| 82 |
// 指定座標系の指定位置が、自座標系のどの位置に相当するかを返す |
| 83 |
bool CoordinateCtrl::getPosition(Position<int>* dst, |
| 84 |
const CoordinateCtrl* crd, |
| 85 |
int x, int y, Angle angle) { |
| 86 |
|
| 87 |
if (crd == NULL) { |
| 88 |
// 渡された座標系が無効な場合、位置計算は行わない |
| 89 |
return false; |
| 90 |
} |
| 91 |
|
| 92 |
// 指定座標系の位置変換 |
| 93 |
Position<int> crd_position; |
| 94 |
const CoordinateCtrl* crd_top = crd; |
| 95 |
set_Position(&crd_position, x, y, angle); |
| 96 |
for (crd_top = crd; |
| 97 |
crd_top->pimpl->parent != NULL; crd_top = crd_top->pimpl->parent) { |
| 98 |
pimpl->convert(crd_position, crd_position, crd_top->pimpl->offset); |
| 99 |
} |
| 100 |
|
| 101 |
// 自座標系の位置変換 |
| 102 |
Position<int> this_origin; |
| 103 |
const CoordinateCtrl* this_top; |
| 104 |
for (this_top = this; |
| 105 |
this_top->pimpl->parent != NULL; this_top = this_top->pimpl->parent) { |
| 106 |
pimpl->convert(this_origin, this_origin, this_top->pimpl->offset); |
| 107 |
} |
| 108 |
|
| 109 |
if (crd_top != this_top) { |
| 110 |
// 最上位の親が同じでない場合、位置計算は無効 |
| 111 |
return false; |
| 112 |
} |
| 113 |
|
| 114 |
// 最終的な位置変換 |
| 115 |
// !!! Position に負号を定義するかな? |
| 116 |
dst->x = crd_position.x - this_origin.x; |
| 117 |
dst->y = crd_position.y - this_origin.y; |
| 118 |
dst->angle = rad(crd_position.angle.to_rad()); |
| 119 |
Position<int> rotate_only; |
| 120 |
rotate_only.angle = rad(-this_origin.angle.to_rad()); |
| 121 |
pimpl->convert(*dst, *dst, rotate_only); |
| 122 |
|
| 123 |
return true; |
| 124 |
} |