본문 바로가기

Programming/C/C++

임의의 벡터간 각도 구하기

벡터간 내적을 이용해서 각도를 구하는 프로그램을 구현해 봤습니다. 일단 내적공식은 저번의 포스팅에서 했다 시피 아래와 같습니다.

   
cos을 기준으로 정리하면 아래와 같습니다.

 
하지만, 일단 벡터는 무조건 단위 행렬로 만들어야 계산이 깔끔해 지기 때문에, 단위행렬의 전제 하에 벡터의 크기는 1. 따라서 아래와 같은 공식을 유도 할 수 있습니다.

 
이 때, Θ를 구하기 위해서는 arc cosine을 이용하면 됩니다. 나오게 된 값을 arc cosine을 이용해서 풀게 되면 Θ를 구할 수 있는 공식인데요, 그렇게 해서 나온 공식 입니다.

 
공식은 모두 다 준비 되었습니다.
   
클래스를 만들어야죠? 벡터는 1x4짜리 크기이며, 단위행렬 만들기와 크기 구하기, 내적 그리고 다른 벡터와 각도 구하기를 할 수 있습니다.
VEC.h
#pragma once
#include <cstdlib>
#include <array>

class VEC
{
private:
	std::tr1::array<float, 4> elem;

public:
	VEC(void);
	VEC(const float &_e0, const float &_e1, const float &_e2, const float &_e3);
	VEC(const std::tr1::array<float, 4> &_vec);
	~VEC(void);

	float &operator()(const size_t &_idx);
	const float &operator()(const size_t &_idx) const;

	void	Normalization();
	float	length();
	float	DotProduct(const VEC &_other);

	float	Anglewith(const VEC &_other);

	void Show();
};

   
구현부에서 중요히 봐야 하는 것은 Anglewith(..) 함수 인데요, 이 함수뿐만 아니라 C에서 제공하는 삼각함수는 모두 radian을 기반으로 계산되는 것이기 때문에 각도로 보려면 180/π를 해주어야 합니다.
   
VEC.cpp
#include "VEC.h"
#include <cstdio>

VEC::VEC(void)
{
	elem[0] = 0.0;
	elem[1] = 0.0;
	elem[2] = 0.0;
	elem[3] = 0.0;
}

VEC::VEC(const float &_e0, const float &_e1, const float &_e2, const float &_e3)
{
	elem[0] = _e0;
	elem[1] = _e1;
	elem[2] = _e2;
	elem[3] = _e3;
}

VEC::VEC(const std::tr1::array<float, 4> &_vec)
{
	elem[0] = _vec[0];
	elem[1] = _vec[1];
	elem[2] = _vec[2];
	elem[3] = _vec[3];
}


VEC::~VEC(void)
{
}

float &VEC::operator()(const size_t &_idx)
{
	if(_idx > 3)
		return elem[0];
	return elem[_idx];
}

const float &VEC::operator()(const size_t &_idx) const
{
	if(_idx > 3)
		return elem[0];
	return elem[_idx];
}

void VEC::Normalization()
{
	float l = length();

	elem[0] = elem[0]/l;
	elem[1] = elem[1]/l;
	elem[2] = elem[2]/l;
	elem[3] = elem[3]/l;
}

float VEC::length()
{
	return sqrt(elem[0]*elem[0] + elem[1]*elem[1] + elem[2]*elem[2] + elem[3]*elem[3]);
}

float VEC::DotProduct(const VEC &_other)
{
	return elem[0]*_other(0)+elem[1]*_other(1)+elem[2]*_other(2)+elem[3]*_other(3);
}

float VEC::Anglewith(const VEC &_other)
{
	return acos(DotProduct(_other))*180.0/3.1415926535;
}


void VEC::Show()
{
	printf("(%lf,   %lf,   %lf,   %lf)\n", elem[0], elem[1], elem[2], elem[3]);
}

   
main.cpp
#include <cstdio>
#include "VEC.h"

int main()
{
	VEC eaxis(1.0, 1.0, 0.0, 0.0);
	VEC xaxis(5.0, 0.0, 0.0, 0.0);

	printf("처음 입력 값\n");
	eaxis.Show();
	xaxis.Show();
	printf("\n");

	eaxis.Normalization();
	xaxis.Normalization();

	printf("단위 행렬로 만든 후 값\n");
	eaxis.Show();
	xaxis.Show();
	printf("\n");

	printf("내적 결과 : %lf\n", eaxis.DotProduct(xaxis));
	printf("각도 결과 : %lf\n", eaxis.Anglewith(xaxis));

	system("pause");
	return 0;
}

   
2차원이라는 가정으로 입력되는 임의의 축은 (1, 1)이고 비교하는 임의의 축은 x축을 바탕으로 했습니다. normalization이 잘 되었는지 확인하는 측면에서 (5, 0)으로 해보았습니다.

 

   
다른 테스트는 진행해 보지 않았지만 일단 원래 이 프로그램을 만든 이유 자체가 '임의의 축을 기준으로 회전을 할 때 어떤 행렬을 곱해야 하는가'에서 출발한 것이므로, 이걸 바탕으로 각 축(x, y, z)에 대해서 임의의 벡터가 이루는 각을 구하고 각 축에 대해서 몇도를 돌려야 하는 행렬에 대입하면 되겠죠? :-D
   
(해보진 않았습니다._ _ㅋㅋ)

'Programming > C/C++' 카테고리의 다른 글

virtual keyword in C++  (0) 2012.08.01
3x3 행렬 코딩  (0) 2011.12.14
C reference 정리 pdf  (0) 2011.09.03
포인터 2차 동적 할당  (0) 2011.02.21
Random double 값 추출하기  (0) 2011.02.10