//---------------------------------------------------------------------------
// 이미지 프로세싱을 DSP가 아닌 워크스테이션 급의 PC(HEDT)에서 처리한다면 OpenCV 라이브러리를 그대로 사용하는 것이 가능하나
// 일단은 DSP를 사용하고 호환성을 유지하기 위하여 OpenCV의 내용중에 필요한 것만 이 모듈에서 직접 구현한다.
//---------------------------------------------------------------------------

#include "open_cv.h"

#include <algorithm>

//---------------------------------------------------------------------------
// 이하는 그라함 알고리즘(Graham’s scan)을 이용하여 ConvexHull을 구하는 내용이다.
// 사용법:
// 1. 먼저 CVPointInitSource()를 호출해준다.
// 2. 이후 외곽을 이루는 점들에 대하여 CVPointAddSource(x, y)를 호출해준다 (호출 순서 무관. 안쪽점 포함되어도 상관없음)
// 3. CVPointConvexHull()를 호출한다. 그러면 CVPointStack에 CVPointStackTop개의 외곽점이 얻어진다.
// 4. 이후 다음의 루프를 돌면서 외곽점들에게 접근할 수 있다.
//    for (int i = 0; i < CVPointStackTop; i++)
//    {
//      int x = CVPointSources[CVPointStack[i]].x;
//      int y = CVPointSources[CVPointStack[i]].y;
//    }
//
// 참고사항:
// CVPointStack에 있는 점들은 시계방향(?)으로 돌고 있다. 점들이 순서대로 돌고 있기 때문에 다른 알고리즘의 적용이 매우 편리하다.
// 이것들은 간격이 일정하지 않은데 간단한 처리를 하면 점들의 간격을 일정하게 만든 점 집합을 새로 만들 수 있다.
// 이렇게 등간격으로 재구성된 Contour를 사용하면 점들의 상호관계를 이용하여 회전/대칭성 테스트 등을 매우 빠르게 할 수 있다.
// 정제의 회전/대칭성/중심좌표/중심축 등을 빠르고 쉽게 찾을 수 있으므로 향후 매칭 알고리즘에 이것을 사용하면 연산속도를 크게 개선시킬 수 있을 것으로 예상한다.
//---------------------------------------------------------------------------
TCVPoint CVPointSources[MAX_CV_POINT];
int CVPointSourceCount;

int CVPointStack[MAX_CV_POINT];
int CVPointStackTop;

bool CVPointCompareY(const TCVPoint &a, const TCVPoint &b)
{
	return a.y == b.y ? a.x > b.x : a.y > b.y;
}

bool CVPointCompareAngle(const TCVPoint &a, const TCVPoint &b)
{
	int c = CVPointCCW(CVPointSources[0], a, b);
	// 점이 직선 상에 있으면 가까운 점을 먼저
	if (c == 0)
	{
		return CVPointDist(CVPointSources[0], a) < CVPointDist(CVPointSources[0], b);
	}
	return c > 0;
}

bool CVPointConvexHull()
{
	CVPointStackTop = 0;

	// 주어진 CVPointSources에 대하여 Graham's Scan (그라함 스캔) 알고리즘으로 Convex Hull (볼록외피)를 구하고 CVPointStack에 저장함.
	if (CVPointSourceCount >= 2)
	{
		std::sort(CVPointSources, CVPointSources + CVPointSourceCount, CVPointCompareY); //Y 값으로 정렬.
		std::sort(CVPointSources + 1, CVPointSources + CVPointSourceCount, CVPointCompareAngle); //가장 왼쪽에 있는 점을 기준으로 반시계방향 정렬

		// 그라함 스캔 알고리즘
		CVPointPushStack(0);
		CVPointPushStack(1);
		for (int i = 2; i < CVPointSourceCount; i++)
		{
			while (CVPointStackTop >= 2 && CVPointCCW(CVPointSources[i], CVPointSources[CVPointStack[CVPointStackTop - 2]], CVPointSources[CVPointStack[CVPointStackTop - 1]]) <= 0)
			{
				CVPointStackTop--;
			}
			CVPointPushStack(i);
		}
		return true;
	}
	return false;
}
//---------------------------------------------------------------------------
