// RecogMain.cpp: implementation of the CRecogMain class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RecogMain.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CRecogMain::CRecogMain()
{
	m_Code = NULL;
	m_CodeNum = 0;
	SymBNNum = 0; m_SymbolBN = NULL;
	memset(CJZBNNum,0,sizeof(int)*3);
	m_JamoBN[0] = NULL;m_JamoBN[1] = NULL;m_JamoBN[2] = NULL;
	m_JamoBTWBN[0] = NULL;m_JamoBTWBN[1] = NULL;
	m_JamoBoundBN = NULL;
}

CRecogMain::~CRecogMain()
{
	EndDIC();

}
/*
________________________________________________________________
  
Function Name	: LoadDic
	
Purpose			: 인식사전들을 적재
		
Input			: No

Output			: No

Return Value	: No

Description		: 적재되는 사전들은;
				  1. 영숫자BN(DigitBN.dic)
				  2. 초성BN(ChoBN.dic)
				  3. 중성BN(JungBN.dic)
				  4. 종성BN(ZongBN.dic)
				  5. 초-중 연결획BN(C2JBN.dic)
				  6. 중-종 연결획BN(J2ZBN.dic)
				  7. 자모위치관계BN(RectBN.dic)
				  들이다.

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
BOOL CRecogMain::LoadDic(char* szDicPath)
{

	FILE* file= NULL;
	char filename[MAX_PATH];


	EndDIC();
	m_Code = CCode::MakeKoreanCodeTable();
	m_CodeNum = KNum;

	int i,j,num;

///////////////////////////////
	sprintf(filename,"%s\\dic\\DigitBN.dic",szDicPath);
	file=fopen(filename,"rb");
	if(file == NULL) return FALSE;
	fread(&SymBNNum,sizeof(int),1,file);
	m_SymbolBN = new JAMOBN[SymBNNum];
	for(j=0;j<SymBNNum;j++){
		m_JamoBNCore.LoadBN(&m_SymbolBN[j],file);
	}
	fclose(file);
/////////////////////////////////////////////

	for(i=0;i<3;i++){
		if(i==0)
			sprintf(filename,"%s\\dic\\ChoBN.dic",szDicPath);
		if(i==1)
			sprintf(filename,"%s\\dic\\JungBN.dic",szDicPath);
		if(i==2)
			sprintf(filename,"%s\\dic\\ZongBN.dic",szDicPath);

		file=fopen(filename,"rb");
		if(file == NULL) return FALSE;
		
		fread(&CJZBNNum[i],sizeof(int),1,file);
		m_JamoBN[i] = (JAMOBN*)malloc(CJZBNNum[i]*sizeof(JAMOBN));
		for(j=0;j<CJZBNNum[i];j++){
			m_JamoBNCore.LoadBN(&m_JamoBN[i][j],file);
		}
		fclose(file);
	}

/////////////////////////////////////////////////

	for(i=0;i<2;i++){
		if(i==0){
			num = CHONum*JUNGNum;
			sprintf(filename,"%s\\dic\\C2JBN.dic",szDicPath);
		}
		if(i==1){
			num = JUNGNum*ZONGNum;
			sprintf(filename,"%s\\dic\\J2ZBN.dic",szDicPath);
		}

		file=fopen(filename,"rb");
		if(file == NULL) return FALSE;
		
		m_JamoBTWBN[i] = (JamoBTWBN*)malloc(num*sizeof(JamoBTWBN));
		for(j=0;j<num;j++){
			m_BTWBNCore.LoadBN(&m_JamoBTWBN[i][j],file);
		}
		fclose(file);
	}
	num = TYPENum;
	sprintf(filename,"%s\\dic\\RectBN.dic",szDicPath);

	file=fopen(filename,"rb");
	if(file == NULL) return FALSE;
	
	m_JamoBoundBN = (JamoBoundBN*)malloc(num*sizeof(JamoBoundBN));
	for(j=0;j<num;j++){
		m_BoundBNCore.LoadBN(&m_JamoBoundBN[j],file);
	}
	fclose(file);

	return TRUE;
}
/*
________________________________________________________________
  
Function Name	: EndDIC
	
Purpose			: 인식을 위해 적재하였던 사전기억을 해제
		
Input			: No

Output			: No

Return Value	: No

Description		: 

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::EndDIC()
{
	int i,j,no;
	if(m_Code!=NULL)free(m_Code);
	if(m_SymbolBN!=NULL){
		for(j=0;j<SymBNNum;j++) {
			m_JamoBNCore.deleteBN(&m_SymbolBN[j]);
		}
		free(m_SymbolBN);
		SymBNNum = 0;
	}
	for(i=0;i<3;i++){
		if(m_JamoBN[i]!=NULL){
			for(j=0;j<CJZBNNum[i];j++) {
				m_JamoBNCore.deleteBN(&m_JamoBN[i][j]);
			}
			free(m_JamoBN[i]);
			CJZBNNum[i] = 0;
		}
	}
	if(m_JamoBTWBN[0] != NULL){
		no=0;
		for(i=0;i<CHONum;i++)for(j=0;j<JUNGNum;j++){
			m_BTWBNCore.deleteBN(&m_JamoBTWBN[0][no]);
			no++;
		}
		free(m_JamoBTWBN[0]);
	}
	if(m_JamoBTWBN[1] != NULL){
		no=0;
		for(i=0;i<JUNGNum;i++)for(j=0;j<ZONGNum;j++){
			m_BTWBNCore.deleteBN(&m_JamoBTWBN[1][no]);
			no++;
		}
		free(m_JamoBTWBN[1]);
	}
	if(m_JamoBoundBN != NULL){
		for(i=0;i<TYPENum;i++){
			m_BoundBNCore.deleteBN(&m_JamoBoundBN[i]);
		}
		free(m_JamoBoundBN);
	}
}

/*
________________________________________________________________
  
Function Name	: GetBoundingBox
	
Purpose			: 입력점 배열의 RealSt부터 RealEd까지의 부분점 배열의 외접4각형을 구한다.
		
Input			: 
	pPts		: 입력점 배열
	PtNum		: 입력점개수
	RealSt		: 입력점 배열에서 고찰하려는 첫점번호
	RealEd		: 입력점 배열에서 고찰하려는 마지막점번호

Output			: 외접4각형

Return Value	: No

Description		: 
Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
RECT CRecogMain::GetBoundingBox(REC_POINT *pPt, int PtNum,int RealSt,int RealEd)
{
	int i;
	RECT r;
	r.left=10000;r.top=10000;r.right=0;r.bottom=0;
	int x,y;
	if(RealSt>=PtNum){
		RealSt = PtNum-1;
	}
	if(RealEd == -1 || RealEd>=PtNum){
		RealEd = PtNum-1;
	}
	for(i=RealSt;i<=RealEd;i++){
		x = (int)max(0,pPt[i].nX);
		y = (int)max(0,pPt[i].nY);
		r.left = min(r.left,x);
		r.top = min(r.top,y);
		r.right = max(r.right,x);
		r.bottom = max(r.bottom,y);
	}
	r.right++;
	r.bottom++;
	return r;
}
/*
________________________________________________________________
  
Function Name	: SortingHuboAry
	
Purpose			: m_Hubo안의 후보 배열을 인식거리를 기준으로 커지는 순으로 정렬.
		
Input			: 미정렬 m_Hubo

Output			: 정렬m_Hubo

Return Value	: No

Description		: 
Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::SortingHuboAry()
{
	HuboAry* pAry = &m_Hubo;
	HUBO temp;
	int i,j;
	int SortNum=pAry->Num;
	for(i=0;i<SortNum;i++)
	{
		for (j = i+1; j <SortNum ; j++){
			if ( pAry->Hubo[i].Dis  > pAry->Hubo[j].Dis )
			{ 	
				memcpy(&temp,&(pAry->Hubo[i]),sizeof(HUBO));
				memcpy(&(pAry->Hubo[i]),&(pAry->Hubo[j]),sizeof(HUBO));
				memcpy(&(pAry->Hubo[j]),&temp,sizeof(HUBO));
			}
		}
	}
	for(i=0;i<SortNum;i++)
	{
		for (j = i+1; j < SortNum ; j++){
			if ( pAry->Hubo[i].Mistake  > pAry->Hubo[j].Mistake  && pAry->Hubo[j].Dis - pAry->Hubo[i].Dis  < 50.f)
			{ 	
				memcpy(&temp,&(pAry->Hubo[i]),sizeof(HUBO));
				memcpy(&(pAry->Hubo[i]),&(pAry->Hubo[j]),sizeof(HUBO));
				memcpy(&(pAry->Hubo[j]),&temp,sizeof(HUBO));
			}
			if ( pAry->Hubo[i].Mistake  == pAry->Hubo[j].Mistake && 
				pAry->Hubo[i].Dis  > pAry->Hubo[j].Dis )
			{ 	
				memcpy(&temp,&(pAry->Hubo[i]),sizeof(HUBO));
				memcpy(&(pAry->Hubo[i]),&(pAry->Hubo[j]),sizeof(HUBO));
				memcpy(&(pAry->Hubo[j]),&temp,sizeof(HUBO));
			}
		}
	}
	
}
/*
________________________________________________________________
  
Function Name	: RecogSymbolDigitAndEng
	
Purpose			: 입력된 점 배열로부터 영어와 숫자를 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	SamNum		: 표본화점 개수

Output			: 영어와 숫자인식후보 배열

Return Value	: No

Description		: 전체 입력점 배열에 대하여 영어와 숫자인식을 진행한다.
				  다음 입력점 배열에 대하여 영어와 숫자사전내에 있는 모든 모형들과의 정합확률을 구하고 				  
				  확률이 가장높은 순서로 MAXHUBO만한 개수의 후보를 얻어서  m_Hubo에 
				  넣는다.

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::RecogSymbolDigitAndEng(REC_POINT* pPts,int* pSamProp,int* pSamNo,int SamNum)
{
	int i,j;//,k;
	HuboAry *pHubo = &m_Hubo;
	HUBO* pPath;
	HUBO  tempPath;
	int minId,sameId;
	int CJZid[3];CJZid[1] = -1;CJZid[2] = -1;
	WORD code;
	int Mistake;
	float dis,minDis;
	JAMOBN* pBN;
	for(i=0;i<SymBNNum;i++){
		pBN = &m_SymbolBN[i];
		if(pBN->StrokeNum<1) continue;
		if(SamNum<pBN->StrokeNum+1) continue;
		dis = m_JamoBNCore.ForwardBN(pBN, pPts,pSamProp,pSamNo,SamNum,Mistake,3);
		if(dis > MAXDIS) continue;
		code = CCode::Sid2SCode(pBN->JamoId);
		CJZid[0] = pBN->JamoId;
		memcpy(tempPath.CJZid,CJZid,sizeof(int)*3);
		tempPath.Code= code;
		tempPath.PtNo[0] = pSamNo[0];
		tempPath.PtNo[1] = pSamNo[SamNum-1];
		tempPath.PtNum = 2;
		tempPath.Dis = dis;
		tempPath.Mistake = 0;
		minDis = 0;
		minId = pHubo->Num;
		sameId = -1;
		for(j=0;j<pHubo->Num;j++){
			pPath = &(pHubo->Hubo[j]);
			if(pPath->Code == tempPath.Code){
				sameId = j;
			}
			if(pPath->Dis > minDis){
				minId = j;
				minDis = pPath->Dis;
			}
		}
		if(pHubo->Num<MAXHUBO) minId = pHubo->Num;
		if(sameId!=-1 )minId = sameId;

		pPath = &(pHubo->Hubo[minId]);
		if(minId == pHubo->Num ){ // New
			memcpy(pPath,&tempPath,sizeof(HUBO));
			pHubo->Num++;
		}else if(pPath->Dis > tempPath.Dis){// Change
			memcpy(pPath,&tempPath,sizeof(HUBO));
		}
	}
}
/*
________________________________________________________________
  
Function Name	: RecogSymbolCho
	
Purpose			: 입력된 점 배열로부터 자음만을 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	SamNum		: 표본화점 개수

Output			: 자음인식후보 배열

Return Value	: No

Description		: 전체 입력점 배열에 대하여 자음인식을 진행한다.
				  다음 입력점 배열에 대하여 자모사전내에 있는 모든 모형들과의 정합확률을 구하고 				  
				  확률이 가장높은 순서로 MAXHUBO만한 개수의 후보를 얻어서  m_Hubo에 
				  넣는다.

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::RecogSymbolCho(REC_POINT* pPts,int* pSamProp,int* pSamNo,int SamNum)
{
	int i,j;//,k;
	HuboAry *pHubo = &m_Hubo;
	HUBO* pPath;
	HUBO  tempPath;
	int minId,sameId;
	int CJZid[3];CJZid[1] = -1;CJZid[2] = -1;
	WORD code;
	int Mistake;
	float dis,minDis;
	JAMOBN* pBN;
	for(i=0;i<CJZBNNum[0];i++){
		pBN = &m_JamoBN[0][i];
		if(pBN->StrokeNum<1) continue;
		if(SamNum<pBN->StrokeNum+1) continue;
		dis = m_JamoBNCore.ForwardBN(pBN, pPts,pSamProp,pSamNo,SamNum,Mistake,3);
		if(dis > pBN->ThDis) continue;
		code = CCode::Cid2CCode(pBN->JamoId);
		CJZid[0] = pBN->JamoId;
		memcpy(tempPath.CJZid,CJZid,sizeof(int)*3);
		tempPath.Code= code;
		tempPath.PtNo[0] = pSamNo[0];
		tempPath.PtNo[1] = pSamNo[SamNum-1];
		tempPath.PtNum = 2;
		tempPath.Dis = dis;
		tempPath.Mistake = Mistake;
		minDis = 0;
		minId = pHubo->Num;
		sameId = -1;
		for(j=0;j<pHubo->Num;j++){
			pPath = &(pHubo->Hubo[j]);
			if(pPath->Code == tempPath.Code){
				sameId = j;
			}
			if(pPath->Dis > minDis){
				minId = j;
				minDis = pPath->Dis;
			}
		}
		if(pHubo->Num<MAXHUBO) minId = pHubo->Num;
		if(sameId!=-1 )minId = sameId;

		pPath = &(pHubo->Hubo[minId]);
		if(minId == pHubo->Num ){ // New
			memcpy(pPath,&tempPath,sizeof(HUBO));
			pHubo->Num++;
		}else if(pPath->Dis > tempPath.Dis){// Change
			memcpy(pPath,&tempPath,sizeof(HUBO));
		}
	}
}
void CRecogMain::RecogSymbolJung(REC_POINT* pPts,int* pSamProp,int* pSamNo,int SamNum)
{
	int i,j;//,k;
	HuboAry *pHubo = &m_Hubo;
	HUBO* pPath;
	HUBO  tempPath;
	int minId,sameId;
	int CJZid[3];CJZid[0] = -1;CJZid[2] = -1;
	WORD code;
	int Mistake;
	float dis,minDis;
	JAMOBN* pBN;
	for(i=0;i<CJZBNNum[1];i++){
		pBN = &m_JamoBN[1][i];
		if(pBN->StrokeNum<1) continue;
		if(SamNum<pBN->StrokeNum+1) continue;
		dis = m_JamoBNCore.ForwardBN(pBN, pPts,pSamProp,pSamNo,SamNum,Mistake,3);
		if(dis > pBN->ThDis) continue;
		code = CCode::Jid2JCode(pBN->JamoId);
		CJZid[1] = pBN->JamoId;
		memcpy(tempPath.CJZid,CJZid,sizeof(int)*3);
		tempPath.Code= code;
		tempPath.PtNo[0] = pSamNo[0];
		tempPath.PtNo[1] = pSamNo[SamNum-1];
		tempPath.PtNum = 2;
		tempPath.Dis = dis;
		tempPath.Mistake = Mistake;
		minDis = 0;
		minId = pHubo->Num;
		sameId = -1;
		for(j=0;j<pHubo->Num;j++){
			pPath = &(pHubo->Hubo[j]);
			if(pPath->Code == tempPath.Code){
				sameId = j;
			}
			if(pPath->Dis > minDis){
				minId = j;
				minDis = pPath->Dis;
			}
		}
		if(pHubo->Num<MAXHUBO) minId = pHubo->Num;
		if(sameId!=-1 )minId = sameId;

		pPath = &(pHubo->Hubo[minId]);
		if(minId == pHubo->Num ){ // New
			memcpy(pPath,&tempPath,sizeof(HUBO));
			pHubo->Num++;
		}else if(pPath->Dis > tempPath.Dis){// Change
			memcpy(pPath,&tempPath,sizeof(HUBO));
		}
	}
}
void CRecogMain::RecogSymbolZong(REC_POINT* pPts,int* pSamProp,int* pSamNo,int SamNum)
{
	int i,j;//,k;
	HuboAry *pHubo = &m_Hubo;
	HUBO* pPath;
	HUBO  tempPath;
	int minId,sameId;
	int CJZid[3];CJZid[0] = -1;CJZid[1] = -1;
	WORD code;
	int Mistake;
	float dis,minDis;
	JAMOBN* pBN;
	for(i=0;i<CJZBNNum[2];i++){
		pBN = &m_JamoBN[2][i];
		if(pBN->StrokeNum<1) continue;
		if(SamNum<pBN->StrokeNum+1) continue;
		dis = m_JamoBNCore.ForwardBN(pBN, pPts,pSamProp,pSamNo,SamNum,Mistake,3);
		if(dis > pBN->ThDis) continue;
		code = CCode::Zid2ZCode(pBN->JamoId);
		CJZid[2] = pBN->JamoId;
		memcpy(tempPath.CJZid,CJZid,sizeof(int)*3);
		tempPath.Code= code;
		tempPath.PtNo[0] = pSamNo[0];
		tempPath.PtNo[1] = pSamNo[SamNum-1];
		tempPath.PtNum = 2;
		tempPath.Dis = dis;
		tempPath.Mistake = Mistake;
		minDis = 0;
		minId = pHubo->Num;
		sameId = -1;
		for(j=0;j<pHubo->Num;j++){
			pPath = &(pHubo->Hubo[j]);
			if(pPath->Code == tempPath.Code){
				sameId = j;
			}
			if(pPath->Dis > minDis){
				minId = j;
				minDis = pPath->Dis;
			}
		}
		if(pHubo->Num<MAXHUBO) minId = pHubo->Num;
		if(sameId!=-1 )minId = sameId;

		pPath = &(pHubo->Hubo[minId]);
		if(minId == pHubo->Num ){ // New
			memcpy(pPath,&tempPath,sizeof(HUBO));
			pHubo->Num++;
		}else if(pPath->Dis > tempPath.Dis){// Change
			memcpy(pPath,&tempPath,sizeof(HUBO));
		}
	}
}
/*
________________________________________________________________
  
Function Name	: RecogKorean
	
Purpose			: 입력된 점 배열로부터 한글을 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	SamNum		: 표본화점 개수

Output			: 한글인식후보 배열

Return Value	: No

Description		: 전체 입력점 배열에 대하여 한글인식을 진행한다.
				  여기서는 동적계획법으로 각이한 초성+중성+종성경로중에서 정합확률이 가장큰순서대로 
				  정렬하여 한글인식후보 배열을 생성하고 첫후보를 인식결과로 반환한다.				  

  Ref Journal		: [1] "Bayesian network modeling of strokes and their relationships for on-line handwriting 
  						recognition"   Sung-Jung Cho*, Jin H. Kim   Pattern Recognition 37(2004) 253-264p
		
					  [2] "Bayesian Network Modeling of Hangul Characters for On-line Handwriting Recognition"  
							Sung-Jung Cho*, Jin H. Kim   ICDAR (2003), pp. 207-211 vol.1
	
date			: 2009/07/5
________________________________________________________________
*/
WORD CRecogMain::RecogKorean(REC_POINT* pPts,int* pSamProp,int* pSamNo,int SamNum)
{
	int num = SamNum;
	if(num<3) return -1;
	int i,t;
	if(num >= MAXSAMNUM) return -1;
	HuboPath* path = m_CJZPath;
	memset(path,0,sizeof(HuboPath)*MAXSAMNUM);
	memset(&m_Hubo,0,sizeof(HuboAry));
	for(t=1;t<SamNum-1;t++){
		if(pSamProp[t]==NON_CJZ_Flag)continue;
		if(t<SamNum-2)
			if(pSamProp[t]!=DOWN_Flag)
				RecogChoSung(pPts,pSamProp,pSamNo,t);
		for(i=1;i<t;i++){
			if(pSamProp[i]==NON_CJZ_Flag)continue;
			if(path[i].Hubo1.Num!=0){
				if(pSamProp[t]!=UP_Flag)
					RecogCho2Jung(pPts,pSamProp,pSamNo,i,t);
			}
			if(path[i].Hubo2.Num!=0){
				if(pSamProp[i]!=UP_Flag&&pSamProp[t]!=DOWN_Flag)
					RecogJungSung(pPts,pSamProp,pSamNo,i,t);
			}
			if(path[i].Hubo3.Num!=0){
				if(pSamProp[t]!=UP_Flag)
					RecogJung2Zong(pPts,pSamProp,pSamNo,i,t);
			}
		}
	}
	t = SamNum-1;
	for(i=2;i<t-1;i++){
		if(pSamProp[i]==NON_CJZ_Flag)continue;
		if(path[i].Hubo2.Num!=0){
			if(pSamProp[i]!=UP_Flag)
				FinalRecogJungSung(pPts,pSamProp,pSamNo,i,t);
		}
		if(path[i].Hubo4.Num!=0){
			if(pSamProp[i]!=UP_Flag)
				FinalRecogZongSung(pPts,pSamProp,pSamNo,i,t);
		}
	}

	SortingHuboAry();
	if(m_Hubo.Num > 0){
		return m_Hubo.Hubo[0].Code;
	}else{
		return 0;
	}

}
/*
________________________________________________________________
  
Function Name	: RecogChoSung
	
Purpose			: 입력된 점 배열로부터 초성을 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	CurNo		: 첫점으로부터 시작하여 인식하려는 마지막표본점번호

Output			: 초성인인식후보 배열

Return Value	: No

Description		: pSamNo[0]부터 pSamNo[CurNo]까지의 점 배열에 대하여 초성인식을 진행한다.
				  먼저 pSamNo[0]부터 pSamNo[CurNo]까지의 점 배열을 64*64크기로 2차정규화를 진행.
				  다음 정규화된 점 배열을 초성사전내에 있는 모든 모형들과의 정합확률을 구하여 
				  확률이 가장높은 순서로 MAXHUBONUM1만한 개수의 후보를 얻어서  m_CJZPath[CurNo].Hubo1에 
				  넣는다.

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::RecogChoSung(REC_POINT* pPts,int* pSamProp,int* pSamNo,int CurNo)
{
	RECT rt = GetBoundingBox(pPts,pSamNo[CurNo]+1,pSamNo[0],pSamNo[CurNo]);
	int i,j;//,k;
	
	float left = (float)rt.left;
	float top = (float)rt.top;
	float Width = (float)(rt.right - rt.left);
	float Height = (float)(rt.bottom - rt.top);
	REC_POINT* pNRtPts = m_pNRtPts;
	float rateW,rateH;
	rateW = (float)(W1-1)/Width;
	rateH = (float)(H1-1)/Height;
	for(i=0;i<=pSamNo[CurNo];i++){
		pNRtPts[i].nX = (pPts[i].nX-left)*rateW;
		pNRtPts[i].nY = (pPts[i].nY-top)*rateH;
	}
	float dis,minDis;
	JAMOBN* pBN;
	ChoHubo* pHubo = &(m_CJZPath[CurNo].Hubo1);
	ChoPath* pPath;
	int minId,sameId;
	int Mistake=0;
	for(i=0;i<CJZBNNum[0];i++){
		pBN = &m_JamoBN[0][i];
		if(pBN->StrokeNum<1) continue;
		if(CurNo<pBN->StrokeNum) continue;
		dis = m_JamoBNCore.ForwardBN(pBN, pNRtPts,pSamProp,pSamNo,CurNo+1,Mistake,2);
		
		if(dis > pBN->ThDis) 
			continue;
		if(pBN->GrpId==0 && pHubo->Num<MAXHUBONUM1){
			minId = pHubo->Num;
		}else{
			minDis = 0;
			minId = pHubo->Num;
			sameId = -1;
			for(j=0;j<pHubo->Num;j++){
				pPath = &(pHubo->Hubo[j]);
				if(pPath->ChoId == pBN->JamoId){
					sameId = j;
				}
				if(pPath->SumDis > minDis){
					minId = j;
					minDis = pPath->SumDis;
				}
			}
			if(pHubo->Num<MAXHUBONUM1) minId = pHubo->Num;
			if(sameId!=-1 )minId = sameId;
		}
		pPath = &(pHubo->Hubo[minId]);
		if(minId == pHubo->Num ){ // New
			pPath->ChoId = pBN->JamoId;
			pPath->PtNo = CurNo;
			pPath->rt = rt;
			pPath->SumDis = dis;
			pPath->Mistake = Mistake;
			pHubo->Num++;
		}else if(pPath->SumDis > dis){// Change
			pPath->ChoId = pBN->JamoId;
			pPath->PtNo = CurNo;
			pPath->rt = rt;
			pPath->Mistake = Mistake;
			pPath->SumDis = dis;
		}
	}
}
/*
________________________________________________________________
  
Function Name	: RecogJungSung
	
Purpose			: 입력된 점 배열로부터 중성을 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	st			: pSamNo에서 연결획시작으로 보는 표본점번호
	ed			: pSamNo에서 연결획끝으로 보는 표본점번호

Output			: 중성인식후보 배열

Return Value	: No

Description		: pSamNo[st]부터 pSamNo[ed]까지의 점 배열에 대하여 중성인식을 진행한다.
				  먼저 pSamNo[st]부터 pSamNo[ed]까지의 점 배열을 64*64크기로 2차정규화를 진행한다.
				  초성인식때와는 달리 이 정규화에서는 중성의 구조적특성상 너비/높이비가 크게 차이나기때문에 
				  그 외접4각형의 너비 혹은 높이비율중 작은것으로 크기 64*64로 선형정규화한다.
				  그리고 m_CJZPath[st].hubo2에 등록되어있는 모든 초성-중성 연결획후보들에 대하여 해당한 
				  중성인식을 진행하여 개별초성정합확률과 초성-중성 연결획정합확률,그리고 중성정합확률의 
				  확률이 가장 큰 순서대로  MAXHUBONUM3만한 개수의 후보를 얻어서  m_CJZPath[ed].Hubo3에 넣는다. 				  				  
				  이때 초성과 중성사이의 위치와 관계되는 자모호상 관련확률(JamoBoundBN)을 구한다.

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::RecogJungSung(REC_POINT* pPts,int* pSamProp,int* pSamNo,int st,int ed)
{
	RECT rt = GetBoundingBox(pPts,pSamNo[ed]+1,pSamNo[st],pSamNo[ed]);
	float left = (float)rt.left;
	float top = (float)rt.top;
	float Width = (float)(rt.right - rt.left);
	float Height = (float)(rt.bottom - rt.top);
	REC_POINT* pNRtPts = m_pNRtPts;
	int i,j,k;
	float offx=0,offy=0;
	float rate;
	if((float)(H1-1)/Height>(float)(W1-1)/Width){
		rate = (float)(W1-1)/Width;
		offy = (((float)H1 - Height*rate)/2.0f);
	}else{
		rate = (float)(H1-1)/Height;
		offx = (((float)W1 - Width*rate)/2.0f);
	}
	for(i=pSamNo[st];i<=pSamNo[ed];i++){
		pNRtPts[i].nX = (pPts[i].nX-left)*rate+offx;
		pNRtPts[i].nY = (pPts[i].nY-top)*rate+offy;
	}

	float dis = MAXDIS,minDis,RectDis;
	float thRectDis = 200.0f;
	JAMOBN* pBN;
	JamoBoundBN* pRectBN;
	C2JHubo* pPreHubo = &(m_CJZPath[st].Hubo2);
	JungHubo* pHubo = &(m_CJZPath[ed].Hubo3);
	C2JPath* pPrePath;
	JungPath* pPath;
	JungPath  tempPath;
	int minId,sameId;
	int preIamoId = -1,nType;
	BOOL bJamoFirst;
	int Mistake;
	for(i=0;i<CJZBNNum[1];i++){
		pBN = &m_JamoBN[1][i];
		if(pBN->StrokeNum<1) continue;
		bJamoFirst = TRUE;
		nType = CCode::GetJungType(pBN->JamoId)+3;
		pRectBN = &m_JamoBoundBN[nType];
		for(k=0;k<pPreHubo->Num;k++){
			pPrePath = &(pPreHubo->Hubo[k]);
			if(pPrePath->JungId != pBN->JamoId) continue;
			m_BoundBNCore.SetDataInRect(pRectBN,0,pPrePath->cho.rt);
			m_BoundBNCore.SetDataInRect(pRectBN,1,rt);
			RectDis = m_BoundBNCore.ForwardRect(pRectBN,0)+m_BoundBNCore.ForwardRect(pRectBN,1);
	
			if(RectDis > pRectBN->pRect[0]->ThDis+pRectBN->pRect[1]->ThDis) continue;
			if(bJamoFirst){
				dis = m_JamoBNCore.ForwardBN(pBN, pNRtPts,&pSamProp[st],&pSamNo[st],ed-st+1,Mistake,2);
				preIamoId = pBN->JamoId;
				bJamoFirst = FALSE;
			}
			if(dis > pBN->ThDis) break;
			RectDis += dis; 
			memcpy(&(tempPath.c2J),pPrePath,sizeof(C2JPath));
			tempPath.JungId = pBN->JamoId;
			tempPath.PtNo = ed;
			tempPath.SumDis = tempPath.c2J.SumDis+RectDis;
			tempPath.Mistake = Mistake;
			tempPath.rt = rt;
		////////////////// register Current Path ////////////
			minDis = 0;
			minId = pHubo->Num;
			sameId = -1;
			for(j=0;j<pHubo->Num;j++){
				pPath = &(pHubo->Hubo[j]);
				if(pPath->JungId == tempPath.JungId && pPath->c2J.cho.ChoId == tempPath.c2J.cho.ChoId){
					sameId = j;
				}
				if(pPath->SumDis > minDis){
					minId = j;
					minDis = pPath->SumDis;
				}
			}
			if(pHubo->Num<MAXHUBONUM3) minId = pHubo->Num;
			if(sameId!=-1 )minId = sameId;

			pPath = &(pHubo->Hubo[minId]);
			if(minId == pHubo->Num ){ // New
				memcpy(pPath,&tempPath,sizeof(JungPath));
				pHubo->Num++;
			}else if(pPath->SumDis > tempPath.SumDis){// Change
				memcpy(pPath,&tempPath,sizeof(JungPath));
			}
		}
	}
}
/*
________________________________________________________________
  
Function Name	: FinalRecogJungSung
	
Purpose			: 고찰하는 점이 입력점 배열의 끝점인 경우에 비받침문자(중성으로 끝나는 )라고 보고
				  최종적인 문자인식후보 배열을 생성하는것.
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	st			: pSamNo에서 연결획시작으로 보는 표본점번호
	ed			: pSamNo에서 마지막 표본점번호

Output			: 비받침문자 인식후보 배열

Return Value	: No

Description		: pSamNo[st]부터 pSamNo[ed]까지의 점 배열에 대하여 중성인식을 진행한다.
				  먼저 pSamNo[st]부터 pSamNo[ed]까지의 점 배열을 64*64크기로 2차정규화를 진행한다.
				  초성인식때와는 달리 이 정규화에서는 중성의 구조적특성상 너비/높이비가 크게 차이나기때문에 
				  그 외접4각형의 너비 혹은 높이비율중 작은것으로 크기 64*64로 선형정규화한다.
				  그리고 m_CJZPath[st].hubo2에 등록되어있는 모든 초성-중성 연결획후보들에 대하여 해당한 
				  중성인식을 진행하여 최종인식거리(정합확률)를 구하고 그것이 가장 큰 순서대로 
				  MAXHUBONUM만한 개수의 후보를 얻어서 최종인식후보 배열m_Hubo에 넣는다. 				  				  				  

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::FinalRecogJungSung(REC_POINT* pPts,int* pSamProp,int* pSamNo,int st,int ed)
{
	RECT rt = GetBoundingBox(pPts,pSamNo[ed]+1,pSamNo[st],pSamNo[ed]);
	float left = (float)rt.left;
	float top = (float)rt.top;
	float Width = (float)(rt.right - rt.left);
	float Height = (float)(rt.bottom - rt.top);
	REC_POINT* pNRtPts = m_pNRtPts;
	int i,j,k;
	float offx=0,offy=0;
	float rate;
	if((float)(H1-1)/Height>(float)(W1-1)/Width){
		rate = (float)(W1-1)/Width;
		offy = (((float)H1 - Height*rate)/2.0f);
	}else{
		rate = (float)(H1-1)/Height;
		offx = (((float)W1 - Width*rate)/2.0f);
	}
	for(i=pSamNo[st];i<=pSamNo[ed];i++){
		pNRtPts[i].nX = (pPts[i].nX-left)*rate+offx;
		pNRtPts[i].nY = (pPts[i].nY-top)*rate+offy;
	}
	float dis = MAXDIS,minDis,RectDis;
	JAMOBN* pBN;
	JamoBoundBN* pRectBN;
	C2JHubo* pPreHubo = &(m_CJZPath[st].Hubo2);
	HuboAry *pHubo = &m_Hubo;
	C2JPath* pPrePath;
	HUBO* pPath;
	HUBO  tempPath;
	int minId,sameId;
	int preIamoId = -1,nType;
	BOOL bJamoFirst;
	int CJZid[3];CJZid[2] = -1;
	WORD code;
	int Mistake;
	for(i=0;i<CJZBNNum[1];i++){
		pBN = &m_JamoBN[1][i];
		if(pBN->StrokeNum<1) continue;

		bJamoFirst = TRUE;

		nType = CCode::GetJungType(pBN->JamoId);
		pRectBN = &m_JamoBoundBN[nType];
		for(k=0;k<pPreHubo->Num;k++){
			pPrePath = &(pPreHubo->Hubo[k]);
			if(pPrePath->JungId != pBN->JamoId) continue;
			CJZid[0] = pPrePath->cho.ChoId;
			CJZid[1] = pPrePath->JungId;
			if(CCode::CJZid2Code(CJZid,code) == FALSE)continue;
			m_BoundBNCore.SetDataInRect(pRectBN,0,pPrePath->cho.rt);
			m_BoundBNCore.SetDataInRect(pRectBN,1,rt);
			RectDis = m_BoundBNCore.ForwardBN(pRectBN);
			if(RectDis > pRectBN->ThDis) continue;
			if(bJamoFirst){
				dis = m_JamoBNCore.ForwardBN(pBN, pNRtPts,&pSamProp[st],&pSamNo[st],ed-st+1,Mistake,2);
				preIamoId = pBN->JamoId;
				bJamoFirst = FALSE;
			}
			if(dis == MAXDIS) break;
			RectDis += dis; 
			memcpy(tempPath.CJZid,CJZid,sizeof(int)*3);
			tempPath.Code= code;
			tempPath.PtNo[0] = pSamNo[0];
			tempPath.PtNo[1] = pSamNo[pPrePath->cho.PtNo];
			tempPath.PtNo[2] = pSamNo[pPrePath->PtNo];
			tempPath.PtNo[3] = pSamNo[ed];
			tempPath.PtNum = 4;
			tempPath.Dis = pPrePath->SumDis+RectDis;
			tempPath.Mistake = pPrePath->Mistake+pPrePath->cho.Mistake+Mistake;

		////////////////// register Current Path ////////////
			minDis = 0;
			minId = pHubo->Num;
			sameId = -1;
			for(j=0;j<pHubo->Num;j++){
				pPath = &(pHubo->Hubo[j]);
				if(pPath->CJZid[0] == tempPath.CJZid[0] && pPath->CJZid[1] == tempPath.CJZid[1]
					&& pPath->CJZid[2] == tempPath.CJZid[2]){
					sameId = j;
				}
				if(pPath->Dis > minDis){
					minId = j;
					minDis = pPath->Dis;
				}
			}
			if(pHubo->Num<MAXHUBO) minId = pHubo->Num;
			if(sameId!=-1 )minId = sameId;

			pPath = &(pHubo->Hubo[minId]);
			if(minId == pHubo->Num ){ // New
				memcpy(pPath,&tempPath,sizeof(HUBO));
				pHubo->Num++;
			}else if(pPath->Dis > tempPath.Dis){// Change
				memcpy(pPath,&tempPath,sizeof(HUBO));
			}
		}
	}
}
/*
________________________________________________________________
  
Function Name	: FinalRecogZongSung
	
Purpose			: 고찰하는 점이 입력점 배열의 끝점인 경우에 받침문자(종성으로 끝나는 )라고 보고
				  최종적인 문자인식후보 배열을 생성하는것.
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	st			: pSamNo에서 연결획시작으로 보는 표본점번호
	ed			: pSamNo에서 마지막 표본점번호

Output			: 받침문자 인식후보 배열

Return Value	: No

Description		: pSamNo[st]부터 pSamNo[ed]까지의 점 배열에 대하여 종성인식을 진행한다.
				  먼저 pSamNo[st]부터 pSamNo[ed]까지의 점 배열을 64*64크기로 선형정규화를 진행한다.
				   그리고 m_CJZPath[st].hubo4에 등록되어있는 모든 중성-종성 연결획후보들에 대하여 해당한 
				  종성인식을 진행하여 최종인식거리(정합확률)를 구하고 그것이 가장 큰 순서대로 
				  MAXHUBONUM만한 개수의 후보를 얻어서 최종인식후보 배열m_Hubo에 넣는다. 				  				  				  

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::FinalRecogZongSung(REC_POINT* pPts,int* pSamProp,int* pSamNo,int st,int ed)
{
	RECT rt = GetBoundingBox(pPts,pSamNo[ed]+1,pSamNo[st],pSamNo[ed]);
	float left = (float)rt.left;
	float top = (float)rt.top;
	float Width = (float)(rt.right - rt.left);
	float Height = (float)(rt.bottom - rt.top);
	REC_POINT* pNRtPts = m_pNRtPts;
	int i,j,k;
	float rateW,rateH;
	rateW = (float)(W1-1)/Width;
	rateH = (float)(H1-1)/Height;
	for(i=pSamNo[st];i<=pSamNo[ed];i++){
		pNRtPts[i].nX = (pPts[i].nX-left)*rateW;
		pNRtPts[i].nY = (pPts[i].nY-top)*rateH;
	}
	float dis = MAXDIS,minDis,RectDis;
	JAMOBN* pBN;
	JamoBoundBN* pRectBN;
	J2ZHubo* pPreHubo = &(m_CJZPath[st].Hubo4);
	HuboAry *pHubo = &m_Hubo;
	J2ZPath* pPrePath;
	HUBO* pPath;
	HUBO  tempPath;
	int minId,sameId;
	int preIamoId = -1,nType;
	BOOL bJamoFirst;
	int CJZid[3];
	WORD code;
	int Mistake;
	for(i=0;i<CJZBNNum[2];i++){
		pBN = &m_JamoBN[2][i];
		if(pBN->StrokeNum<1) continue;
	
			bJamoFirst = TRUE;

		for(k=0;k<pPreHubo->Num;k++){
			pPrePath = &(pPreHubo->Hubo[k]);
			if(pPrePath->ZongId != pBN->JamoId) continue;
			CJZid[0] = pPrePath->Jung.c2J.cho.ChoId;
			CJZid[1] = pPrePath->Jung.JungId;
			CJZid[2] = pPrePath->ZongId;
			if(CCode::CJZid2Code(CJZid,code) == FALSE)continue;
			nType = CCode::GetJungType(CJZid[1])+3;
			pRectBN = &m_JamoBoundBN[nType];
			m_BoundBNCore.SetDataInRect(pRectBN,0,pPrePath->Jung.c2J.cho.rt);
			m_BoundBNCore.SetDataInRect(pRectBN,1,pPrePath->Jung.rt);
			m_BoundBNCore.SetDataInRect(pRectBN,2,rt);
			RectDis = m_BoundBNCore.ForwardRect(pRectBN,2);
			if(RectDis > pRectBN->pRect[2]->ThDis) continue;
			if(bJamoFirst){
				dis = m_JamoBNCore.ForwardBN(pBN, pNRtPts,&pSamProp[st],&pSamNo[st],ed-st+1,Mistake,2);
				preIamoId = pBN->JamoId;
				bJamoFirst = FALSE;
			}
		
			if(dis == MAXDIS) break;
			RectDis += dis; 
			memcpy(tempPath.CJZid,CJZid,sizeof(int)*3);
			tempPath.Code= code;
			tempPath.PtNo[0] = pSamNo[0];
			tempPath.PtNo[1] = pSamNo[pPrePath->Jung.c2J.cho.PtNo];
			tempPath.PtNo[2] = pSamNo[pPrePath->Jung.c2J.PtNo];
			tempPath.PtNo[3] = pSamNo[pPrePath->Jung.PtNo];
			tempPath.PtNo[4] = pSamNo[pPrePath->PtNo];
			tempPath.PtNo[5] = pSamNo[ed];
			tempPath.PtNum = 6;
			tempPath.Dis = pPrePath->SumDis+RectDis;
			tempPath.Mistake = pPrePath->Mistake+pPrePath->Jung.c2J.Mistake+pPrePath->Jung.Mistake+pPrePath->Jung.c2J.cho.Mistake+Mistake;
			
		////////////////// register Current Path ////////////
			minDis = 0;
			minId = pHubo->Num;
			sameId = -1;
			for(j=0;j<pHubo->Num;j++){
				pPath = &(pHubo->Hubo[j]);
				if(pPath->CJZid[0] == tempPath.CJZid[0] && pPath->CJZid[1] == tempPath.CJZid[1]
					&& pPath->CJZid[2] == tempPath.CJZid[2]){
					sameId = j;
				}
				if(pPath->Dis > minDis){
					minId = j;
					minDis = pPath->Dis;
				}
			}
			if(pHubo->Num<MAXHUBO) minId = pHubo->Num;
			if(sameId!=-1 )minId = sameId;

			pPath = &(pHubo->Hubo[minId]);
			if(minId == pHubo->Num ){ // New
				memcpy(pPath,&tempPath,sizeof(HUBO));
				pHubo->Num++;
			}else if(pPath->Dis > tempPath.Dis){// Change
				memcpy(pPath,&tempPath,sizeof(HUBO));
			}
		}
	}
}
/*
________________________________________________________________
  
Function Name	: RecogCho2Jung
	
Purpose			: 입력된 점 배열로부터 초성-중성 연결획을 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	st			: pSamNo에서 연결획시작으로 보는 표본점번호
	ed			: pSamNo에서 연결획끝으로 보는 표본점번호

Output			: 초성-중성 연결획 인식후보 배열

Return Value	: No

Description		: pSamNo[st]부터 pSamNo[ed]까지의 점 배열에 대하여 초성-중성인식을 진행한다.
				  m_CJZPath[st].hubo1에 등록되어있는 모든 초성후보들에 대하여 가능한 
				  초성-중성 연결획 인식을 진행하여 개별초성정합확률과 초성-중성 연결획정합확률의 
				  확률이 가장 큰 순서대로  MAXHUBONUM2만한 개수의 후보를 얻어서  m_CJZPath[ed].Hubo2에 넣는다. 
				  이때 초성-중성간 ㄱ연결획호모형사전이 참조된다.
				  (m_JamoBTWBN[0],m_JamoBTWBN[0]:초성-중성 연결획BN,m_JamoBTWBN[1]:중성-종성 연결획BN)

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::RecogCho2Jung(REC_POINT* pPts,int *pSamProp,int* pSamNo,int st,int ed)
{
	int i,j,k;
	float dis = MAXDIS,minDis;
	float thBTWDis = 200.0f;
	JamoBTWBN* pBN;
	ChoHubo* pPreHubo = &(m_CJZPath[st].Hubo1);
	C2JHubo* pHubo = &(m_CJZPath[ed].Hubo2);
	ChoPath* pPrePath;
	C2JPath* pPath;
	C2JPath  tempPath;
	int minId,sameId;
	int choId,JungId,no;
	int Mistake=1;

	Mistake = 0;
	for(i=0;i<pPreHubo->Num;i++)
	{
		pPrePath = &(pPreHubo->Hubo[i]);
		choId = pPrePath->ChoId;
		for(k=0;k<JUNGNum;k++)
		{
			JungId = k;
			no = choId*JUNGNum+JungId;
			pBN = &m_JamoBTWBN[0][no];
			if(pBN->bStudied == FALSE) continue;
			m_BTWBNCore.SetDataInBN(pBN,pPts,pSamNo[st],pSamNo[ed]);
			dis = m_BTWBNCore.ForwardBN(pBN);
			if(dis > pBN->ThDis)
				continue;
			memcpy(&(tempPath.cho),pPrePath,sizeof(ChoPath));
			tempPath.JungId = JungId;
			tempPath.PtNo = ed;
			tempPath.SumDis = tempPath.cho.SumDis+dis;
			tempPath.Mistake =Mistake;
		////////////////// register Current Path ////////////
			minDis = 0;
			minId = pHubo->Num;
			sameId = -1;
			for(j=0;j<pHubo->Num;j++)
			{
				pPath = &(pHubo->Hubo[j]);
				if(pPath->JungId == tempPath.JungId && pPath->cho.ChoId == tempPath.cho.ChoId){
					sameId = j;
				}
				if(pPath->SumDis > minDis){
					minId = j;
					minDis = pPath->SumDis;
				}
			}
			if(pHubo->Num<MAXHUBONUM2) minId = pHubo->Num;
			if(sameId!=-1 )minId = sameId;

			pPath = &(pHubo->Hubo[minId]);
			if(minId == pHubo->Num )// New
			{ 
				memcpy(pPath,&tempPath,sizeof(C2JPath));
				pHubo->Num++;
			}else if(pPath->SumDis > tempPath.SumDis)// Change
			{
				memcpy(pPath,&tempPath,sizeof(C2JPath));
			}
		}
	}
}
/*
________________________________________________________________
  
Function Name	: RecogJung2Zong
	
Purpose			: 입력된 점 배열로부터 중성-종성 연결획을 인식하는것 .
		
Input			:
	pPts		: 입력점 배열
	pSamProp	: 펜up-down정보
	pSamNo		: 표본화점 번호 배열 
	st			: pSamNo에서 연결획시작으로 보는 표본점번호
	ed			: pSamNo에서 연결획끝으로 보는 표본점번호

Output			: 중성-종성 연결획 인식후보 배열

Return Value	: No

Description		: pSamNo[st]부터 pSamNo[ed]까지의 점 배열에 대하여 중성-종성인식을 진행한다.
				  m_CJZPath[st].hubo3에 등록되어있는 모든 중성후보들에 대한 가능한 
				  중성-종성 연결획 인식을 진행하여 개별중성정합확률과 중성-종성 연결획정합확률의 
				  확률이 가장 큰 순서대로  MAXHUBONUM4만한 개수의 후보를 얻어서  m_CJZPath[ed].Hubo4에 넣는다. 
				  이때 중성-종성간 연결획호모형사전(m_JamoBTWBN[1])이 참조된다.
				  (m_JamoBTWBN[0]:초성-중성 연결획BN,m_JamoBTWBN[1]:중성-종성 연결획BN)

Ref Journal		: No
	
date			: 2009/07/5
________________________________________________________________
*/
void CRecogMain::RecogJung2Zong(REC_POINT* pPts,int *pSamProp,int* pSamNo,int st,int ed)
{
	int i,j,k;
	float dis = MAXDIS,minDis;
	float thBTWDis = 200.0f;
	JamoBTWBN* pBN;
	JungHubo* pPreHubo = &(m_CJZPath[st].Hubo3);
	J2ZHubo* pHubo = &(m_CJZPath[ed].Hubo4);
	JungPath* pPrePath;
	J2ZPath* pPath;
	J2ZPath  tempPath;
	int minId,sameId;
	int JungId,ZongId,no;
	int CJZId[3];
	WORD Code;
	int Mistake=1;

	Mistake = 0;
	for(i=0;i<pPreHubo->Num;i++)
	{
		pPrePath = &(pPreHubo->Hubo[i]);
		JungId = pPrePath->JungId;
		CJZId[0] = pPrePath->c2J.cho.ChoId;
		CJZId[1] = JungId;
		for(k=0;k<ZONGNum;k++)
		{
			ZongId = k;
			CJZId[2] = ZongId;
			no = JungId*ZONGNum+ZongId;
			pBN = &m_JamoBTWBN[1][no];
			if(pBN->bStudied == FALSE) continue;
			if(CCode::CJZid2Code(CJZId,Code) == FALSE)continue;
			m_BTWBNCore.SetDataInBN(pBN,pPts,pSamNo[st],pSamNo[ed]);
			dis = m_BTWBNCore.ForwardBN(pBN);
			if(dis > pBN->ThDis) continue;
			memcpy(&(tempPath.Jung),pPrePath,sizeof(JungPath));
			tempPath.ZongId = ZongId;
			tempPath.PtNo = ed;
			tempPath.SumDis = tempPath.Jung.SumDis+dis;
			tempPath.Mistake = Mistake;
		////////////////// register Current Path ////////////
			minDis = 0;
			minId = pHubo->Num;
			sameId = -1;
			for(j=0;j<pHubo->Num;j++)
			{
				pPath = &(pHubo->Hubo[j]);
				if(pPath->ZongId == tempPath.ZongId && pPath->Jung.JungId == tempPath.Jung.JungId
					&& pPath->Jung.c2J.cho.ChoId == tempPath.Jung.c2J.cho.ChoId){
					sameId = j;
				}
				if(pPath->SumDis > minDis){
					minId = j;
					minDis = pPath->SumDis;
				}
			}
			if(pHubo->Num<MAXHUBONUM4) minId = pHubo->Num;
			if(sameId!=-1 )minId = sameId;

			pPath = &(pHubo->Hubo[minId]);
			if(minId == pHubo->Num )// New
			{ 
				memcpy(pPath,&tempPath,sizeof(J2ZPath));
				pHubo->Num++;
			}else if(pPath->SumDis > tempPath.SumDis)// Change
			{
				memcpy(pPath,&tempPath,sizeof(J2ZPath));
			}
		}
	}
}
/*
________________________________________________________________
  
Function Name	: Recog
	
Purpose			: 입력된 점 배열로부터 한글/영어/숫자를 인식하는것
		
Input			:
	pOrgPt		: 입력점 배열
	OrgPtNum	: 입력점수
	pOrgStroke	: 획정보 배열
	nOrgStrkNum	: 획 개수	

Output			: No

Return Value	: 인식된 전각코드(한글/영어/숫자)

Description		: 입력점 배열pOrgPt는 마우스 또는 펜입력장치로 글을 쓸때 입력되는 점 배열이고
				  획정보배열pOrgStroke는 마우스 또는 펜을 down-up시킬때마다 하나씩 생기는 획배열이다. 

Ref Journal		: [1]   "Bayesian network modeling of strokes and their relationships for on-line handwriting 
									recognition"   Sung-Jung Cho*, Jin H. Kim   Pattern Recognition 37(2004) 253-264p
		
				  [2]   "Bayesian Network Modeling of Hangul Characters for On-line Handwriting Recognition"  
									Sung-Jung Cho*, Jin H. Kim   ICDAR (2003), pp. 207-211 vol.1

date			: 2009/07/5
________________________________________________________________
*/
WORD CRecogMain::Recog(OVR_POINT *pOrgPt, int OrgPtNum, STROKE *pOrgStroke,int nOrgStrkNum)
{
	REC_POINT*	pPts;
	int*		pSelNo,*pSamProp,SelNum;
	
	int			NewPtNum,NorPtNum;	
	STROKE		pNewStroke[MAXSTROKENUM];
	int			nStrkNum = nOrgStrkNum;

	pSelNo = m_pSelNo;
	pSamProp = m_pSamProp;
	memset(pSamProp,NON_CJZ_Flag,sizeof(int)*H1*W1);

	//-------------- 잡음제거 및 평활화 -----------
	OVR_POINT* pNewPt= m_PreProcess.NoisProcess(pOrgPt,OrgPtNum,pOrgStroke,pNewStroke,nStrkNum,NewPtNum );
	//---------------------------------------------
	
	//-------------- 정규화 ------------------------------------------------------- 
	OVR_POINT* pNorPt = m_PreProcess.GetNormalizePtsAndStroke(pNewPt,NewPtNum,
													pNewStroke,nStrkNum,pSamProp,pSelNo,SelNum,NorPtNum);
	//-----------------------------------------------------------------------------
	free(pNorPt);

	pPts = m_PreProcess.m_Bec;

	//--------------- 한글 인식 ----------------
	RecogKorean(pPts,pSamProp,pSelNo,SelNum);
	//--------------------------------------------

	//--------------- 자음인식 --------------
	RecogSymbolCho(pPts,pSamProp,pSelNo,SelNum);
	//--------------------------------------------

	//----- 영어/숫자인식을 위하여 크기정규화 및 연속점 배열 만들기 -----
	pNorPt = m_PreProcess.GetNormalizeOnlyHorWPtsAndStroke(pNewPt,NewPtNum,
		pNewStroke,nStrkNum,pSamProp,pSelNo,SelNum,NorPtNum);
	//----------------------------------------------------------------
	
	free(pNewPt);	free(pNorPt);
	
	pPts = m_PreProcess.m_Bec;

	//-------- 영어/숫자인식 ----------------------------
	RecogSymbolDigitAndEng(pPts,pSamProp,pSelNo,SelNum);
	//---------------------------------------------------

	//------- 인식결과 정렬 -------
	SortingHuboAry();
	//-----------------------------

	//--- 1후보를 인식결과로 반환  ---
	if(m_Hubo.Num > 0){
		return m_Hubo.Hubo[0].Code;
	}else{
		return 0;
	}
	//--------------------------------

}
