2012년 10월 19일 금요일

GUI작업에 유용한 산술 함수

//Vector3는 단순히 x,y,z float값을 가지는 구조체를 의미한다.
//Matrix는 4*4 정방행렬의 의미한다.

// 두 지점의 내적을 계산
float dot(const Vector3 v1, const Vector3 v2)
{
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}

// 두지점의 외적을 계산
float cross(const Vector3 v1, const Vector3 v2)
{
return Vector3(vVector1.y * vVector2.z - vVector1.z * vVector2.y,
vVector1.z * vVector2.x - vVector1.x * vVector2.z,
vVector1.x * vVector2.y - vVector1.y * vVector2.x);
}

// 두지점간 거리 계산
float distance(const Vector3 v1, const Vector3 v2)
{
return sqrtf(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
}

// 백터의 정규화(normalize) 처리
Vector3 normalize(const Vector3 v)
{
float fMagnitude = sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
return Vector3(v.x / fMagnitude, v.y / fMagnitude, v.z / fMagnitude);
}

// 지정된 백터의 지점을 행렬값에 따라 어파인 변환처리 수행
Vector3 Vec3TransformCoord(Vector3 pVtIn, Matrix pMatIn)
{
Vector3 pVtOut;

float x = pVtIn.x * pMatIn.m[0][0] + pVtIn.y * pMatIn.m[1][0] + pVtIn.z
* pMatIn.m[2][0] + pMatIn.m[3][0];
float y = pVtIn.x * pMatIn.m[0][1] + pVtIn.y * pMatIn.m[1][1] + pVtIn.z
* pMatIn.m[2][1] + pMatIn.m[3][1];
float z = pVtIn.x * pMatIn.m[0][2] + pVtIn.y * pMatIn.m[1][2] + pVtIn.z
* pMatIn.m[2][2] + pMatIn.m[3][2];
float w = pVtIn.x * pMatIn.m[0][3] + pVtIn.y * pMatIn.m[1][3] + pVtIn.z
* pMatIn.m[2][3] + pMatIn.m[3][3];
pVtOut.x = g_x / g_w;
pVtOut.y = g_y / g_w;
pVtOut.z = g_z / g_w;

return pVtOut;
}

// --------------------------------------------------------------------------------------------------------------
// 아래 isInTriangle함수의 보조 함수
float _inTriangleFunc(Vector3 vt1, Vector3 vt2, Vector3 vt3)
{
return ((vt3.x - vt1.x) * (vt1.y - vt2.y) - (vt3.y - vt1.y) * (vt1.x - vt2.x));
}

// 세점을 연결하는 삼각형 안에 지정된 포인트가 포함되어 있는지 판단
boolean isInTriangle(Vector3 vt1, Vector3 vt2, Vector3 vt3, Vector3 vtFind)
{
float fTemp1, fTemp2;
fTemp1 = _inTriangleFunc(vt1, vt2, vt3);
fTemp2 = _inTriangleFunc(vt1, vt2, vtFind);

if((g_fTemp1 * g_fTemp2) <= 0.0)
return false;

fTemp1 = _inTriangleFunc(vt2, vt3, vt1);

fTemp2 = _inTriangleFunc(vt2, vt3, vtFind);


if((g_fTemp1 * g_fTemp2) <= 0.0)
return false;

fTemp1 = _inTriangleFunc(vt3, vt1, vt2);
fTemp2 = _inTriangleFunc(vt3, vt1, vtFind);

if((fTemp1 * fTemp2) <= 0.0)
return false;

return true;
}
// --------------------------------------------------------------------------------------------------------------


// --------------------------------------------------------------------------------------------------------------
// 3점을 연결로 하는 베지어 곡선 계산
// fMu : 0.0f ~ 1.0f
Vector3 Vec3Bezier3(Vector3 vVector1, Vector3 vVector2, Vector3 vVector3, float fMu)
{
float fMum1, fMum12, fMu2;
fMu2 = fMu * fMu;
fMum1 = 1.0f - fMu;
fMum12 = fMum1 * fMum1;

Vector3 pVtOut;
pVtOut.x = vVector1.x * fMum12 + 2 * vVector2.x * fMum1 * fMu + vVector3.x * fMu2;
pVtOut.y = vVector1.y * fMum12 + 2 * vVector2.y * fMum1 * fMu + vVector3.y * fMu2;
pVtOut.z = vVector1.z * fMum12 + 2 * vVector2.z * fMum1 * fMu + vVector3.z * fMu2;

return pVtOut;
}

// 4점을 연결로 하는 베지어 곡선 계산
// fMu : 0.0f ~ 1.0f
Vector3 Vec3Bezier4(Vector3 pVtOut, Vector3 vVector1, Vector3 vVector2, Vector3 vVector3, Vector3 vVector4, float fMu)
{
float fMum1, fMum13, fMu3;
fMum1 = 1.0f - fMu;
fMum13 = fMum1 * fMum1 * fMum1;
fMu3 = fMu * fMu * fMu;

Vector3 pVtOut;
pVtOut.x = fMum13 * vVector1.x + 3 * fMu * fMum1 * fMum1 * vVector2.x + 3 * fMu * fMu * fMum1 * vVector3.x + fMu3 * vVector4.x;
pVtOut.y = fMum13 * vVector1.y + 3 * fMu * fMum1 * fMum1 * vVector2.y + 3 * fMu * fMu * fMum1 * vVector3.y + fMu3 * vVector4.y;
pVtOut.y = fMum13 * vVector1.z + 3 * fMu * fMum1 * fMum1 * vVector2.z + 3 * fMu * fMu * fMum1 * vVector3.z + fMu3 * vVector4.z;

return pVtOut;
}
// --------------------------------------------------------------------------------------------------------------


// --------------------------------------------------------------------------------------------------------------
// 2점사이의 라디안 값 계산
float Vec3Radian(Vector3 vVector1, Vector3 vVector2)
{
float fRadian;

if(0 == (vVector2.x - vVector1.x))
{
if(vVector1.z > vVector2.z)
return M_PI + M_PI / 2;
else if(vVector1.z < vVector2.z)
return M_PI / 2;
else
return 0;
}
else
{
if(0 == (vVector1.x - vVector2.x))
fRadian = 0;
else
fRadian = (float) Math.atan((vVector1.z - vVector2.z) / (vVector1.x - vVector2.x));

if(0 > (vVector2.x - vVector1.x))
{
fRadian += M_PI;
}
}

return fRadian;
}

// 2점사이의 디그리 값 계산
float Vec3Degree(Vector3 vVector1, Vector3 vVector2)
{
return (Vec3Radian(vVector1, vVector2) * 180.0f / M_PI)
}
// --------------------------------------------------------------------------------------------------------------


// --------------------------------------------------------------------------------------------------------------
// vVector1 지점을 기준으로  vVector2 지점을 방향으로 하는 fDistance거리 만큼의 위치를 얻어옴
Vector3 Vec3PointOnHypotenuse(Vector3 pVtOut, Vector3 vVector1, Vector3 vVector2, float fDistance)
{
float fDx = vVector2.x - vVector1.x;
float fDy = vVector2.y - vVector1.y;

float fLineLength = (float) sqrtf(fDx * fDx + fDy * fDy);
float fScale = fDistance / fLineLength;
pVtOut.x = vVector1.x + fDx * fScale;
pVtOut.y = vVector1.y + fDy * fScale;
pVtOut.z = 0;

return pVtOut;
}


// vVector1, vVector2 두 지점을 잇는 직선과 vVector3, vVector4 두점을 잇는 직선이 교차하는 Point얻어오기
Vector3 Vec3Intersection(Vector3 vVector1, Vector3 vVector2, Vector3 vVector3, Vector3 vVector4)
{
float a1, a2, b1, b2, c1, c2;

a1 = vVector2.y - vVector1.y;
b1 = vVector1.x - vVector2.x;
c1 = vVector2.x * vVector1.y - vVector1.x * vVector2.y;

a2 = vVector4.y - vVector3.y;
b2 = vVector3.x - vVector4.x;
c2 = vVector4.x * vVector3.y - vVector3.x * vVector4.y;

float fDenominator = a1 * b2 - a2 * b1;
if(0 == fDenominator)
{
pVtOut.x = 0;
pVtOut.y = 0;
pVtOut.z = 0;
return pVtOut;
}

pVtOut.x = (b1 * c2 - b2 * c1) / fDenominator;
pVtOut.y = (a2 * c1 - a1 * c2) / fDenominator;
pVtOut.z = 0;
return pVtOut;
}


// --------------------------------------------------------------------------------------------------------------
// 특정 지점으로 부터 입력된 Degree값 방향으로 fDistance만큼 위치한 지점 찾기
void getPosAngle(Vector3 vtIn, float fRadian, float fDistance)
{
Vector3 vtOut;

vtOut.x = (INT)(cosf(fRadian) * fDistance + vtIn.x + 0.5f); // X좌표 보정
vtOut.y = (INT)(sinf(fRadian) * fDistance + vtIn.y + 0.5f); // Y좌표 보정
vtOut.z = vtIn.z;

return vtOut;
}

// 특정 지점으로 부터 입력된 Degree값 방향으로 fDistance만큼 위치한 지점 찾기
Vector3 getPosDegree(Vector3 vtIn, float fDegree, float fDistance)
{
return getPosAngle(vtIn, fDegree / 180.0f * M_PI, fDistance)
}
// --------------------------------------------------------------------------------------------------------------


// --------------------------------------------------------------------------------------------------------------
// 내장 rand없이 대신 사용가능한 랜덤 함수
g_nRandNext = 0;
unsigned long rand(void)
{
g_nRandNext = g_nRandNext * 1103515245 + 12345;
return ((DWORD)(g_nRandNext / 65536) % 32768);
}

/* srand:  set seed for rand() */
void SRandSeed(DWORD seed)
{
g_nRandNext = seed;
}
// --------------------------------------------------------------------------------------------------------------