#include "CPB_Module_Main.h"
#include "CPB_Module.h"
#include "CPB_Global.h"
#include "Global.h"
#include <math.h>

#ifndef TARGET_CPB
#include "Virtual_CPB_System.h"
#else
#include "hardware.h"
#endif

#ifdef PC_SIM
#include <mem.h>
#else
#include "environment.h"
#endif
int CurrentGlobalCamIndex;

volatile int Process_Function = PROCESS_FUNC_NONE;

int Processing_Run_Time;

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ColorSourceImage_Temp[3 * SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT];  //900k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char InspectionArea_Temp[SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT];      //300k

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
short LabelImage_Virtual_Temp[MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char ThreeDImage_Temp[SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT];      //300k

#pragma DATA_ALIGN(128)
#pragma DATA_SECTION(".shared")
unsigned char ThreeDOutLineImage[SYSTEM_CAMERA_WIDTH * SYSTEM_CAMERA_HEIGHT];

#pragma DATA_ALIGN(8)
#pragma DATA_SECTION(".sdram")
unsigned char smallSizeProcessedImage[64 * 48];

int threeDTabletHorizonalLength;
int threeDTabletVerticalLength;

#pragma DATA_ALIGN(128)
#pragma DATA_SECTION(".shared")
int SubcoreProcessingActiveSW[MAX_PROCESSING_CORE_COUNT * CACHE_CONTROL_DUMMY_SIZE];

#pragma DATA_ALIGN(128)
#pragma DATA_SECTION(".shared")
unsigned char SharedImageBuffer[MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT];

#pragma DATA_ALIGN(128)
#pragma DATA_SECTION(".shared")
TSharedProcessingParamsForRotation SharedProcessingParamsForRotation;

#pragma DATA_ALIGN(128)
#pragma DATA_SECTION(".shared")
int SharedJobDistributionForRotation[MAX_PROCESSING_CORE_COUNT * CACHE_CONTROL_DUMMY_SIZE][SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1];

#pragma DATA_ALIGN(128)
#pragma DATA_SECTION(".shared")
int SharedProcessingResultForRotation[(SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1) * CACHE_CONTROL_DUMMY_SIZE];

int TabletSplitLineAngle;

int threeDminX;
int threeDmaxX;
int threeDminY;
int threeDmaxY;

//---------------------------------------------------------------------------
#ifdef __cplusplus
extern "C"
{
#endif  /* __cplusplus */

void CPB_Module_Processing(void)
{
	if (Process_Function == PROCESS_FUNC_INSPECTION)
	{
		CPB_Processing_Inspection();
	}
	else if (Process_Function == PROCESS_FUNC_STUDY_POSITION)
	{
		CPB_Processing_Position(STUDY_MODE);
	}
	else if (Process_Function == PROCESS_FUNC_INSPECTION_POSITION)
	{
		CPB_Processing_Position(INSPECTION_MODE);
	}
	else if (Process_Function == PROCESS_FUNC_SETUP)
	{
		CPB_Processing_Setup();
	}
	else if (Process_Function == PROCESS_FUNC_STUDY)
	{
		CPB_Processing_Study();
	}
	else if (Process_Function == PROCESS_FUNC_INSPECTION_TPB)
	{
		CPB_Processing_Inspection_TPB();
	}
}

//---------------------------------------------------------------------------
void ClearInspectionData(void)
{
	ColorCountClear_Func();
}

//---------------------------------------------------------------------------
void ClearThreeDPositionMultiCoreProcessing(void)
{
#ifndef PC_SIM
	// shared memory에 대한 initial
	// 3D Position의 분할 프로세스 시작 전에 Indicator를 받은 core(main core)에서 clear 수행
	// dummy buffer에 write된 값은 무시
	memset(SubcoreProcessingActiveSW, 0, sizeof(SubcoreProcessingActiveSW));
	cacheWriteBack_ddr3((char *)SubcoreProcessingActiveSW, sizeof(int) * CACHE_CONTROL_DUMMY_SIZE * MAX_PROCESSING_CORE_COUNT);
#endif
}

#ifdef __cplusplus
}
#endif  /* __cplusplus */
//---------------------------------------------------------------------------

void CPB_Processing_Setup(void)
{
	CPBCommonVariableInitial();

	if (CPBSystemSetupData.InspectionType & INSPECTION_MASK_FRONT_FACE)
	{
		if (CPBSystemSetupData.SuctionDiskNumber)
		{
			FrontFaceSetUpDataTransForm(FRONT_FACE, CPBSystemSetupData.SuctionDiskNumber);
		}
	}

	if (CPBSystemSetupData.InspectionType & INSPECTION_MASK_SIDE_FACE_M45 ||
	        CPBSystemSetupData.InspectionType & INSPECTION_MASK_SIDE_FACE_0 ||
	        CPBSystemSetupData.InspectionType & INSPECTION_MASK_SIDE_FACE_P45)
	{
		SideFaceSetUpDataTransForm(CPBSystemSetupData.spbBoardID, 0);
	}

	if (CPBSystemSetupData.InspectionType & INSPECTION_MASK_3D)
	{
		if (CPBSystemSetupData.SuctionDiskNumber)
		{
			SetUpDataTransFormForThreeD(FRONT_FACE_SPECIAL, CPBSystemSetupData.SuctionDiskNumber);
		}
	}

	InitialImageBuffer();
}
//---------------------------------------------------------------------------
void CPB_Processing_Study(void)
{
	int InspectionOrStudy;
	int InspectionKind;

	InspectionOrStudy = STUDY_MODE;

	if ((CurrentGlobalCamIndex + 1) == SD1_2D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_FRONT_FACE_CAMERA_INDEX)
	{
		InspectionKind = FRONT_FACE;
		ProcessingStartForFrontFace(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_3D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_3D_FRONT_FACE_CAMERA_INDEX)
	{
		InspectionKind = FRONT_FACE_3D;
		ProcessingStartForFrontFace_3D(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0x00);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_2D_SIDE_FACE_P45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_SIDE_FACE_P45_CAMERA_INDEX ||
	         (CurrentGlobalCamIndex + 1) == SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX)
	{
		InspectionKind = SIDE_FACE_P45;
		ProcessingStartForSideFace_P45(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_2D_SIDE_FACE_00_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_SIDE_FACE_00_CAMERA_INDEX ||
	         (CurrentGlobalCamIndex + 1) == SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX)
	{
		InspectionKind = SIDE_FACE_0;
		ProcessingStartForSideFace_0(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_2D_SIDE_FACE_M45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_SIDE_FACE_M45_CAMERA_INDEX ||
	         (CurrentGlobalCamIndex + 1) == SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX)
	{
		InspectionKind = SIDE_FACE_M45;
		ProcessingStartForSideFace_M45(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}

	if (InspectionKind == FRONT_FACE_3D)
	{
		memcpy(ThreeDImage_Temp, ThreeD_Image, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	}
	else
	{
		memcpy(ThreeDImage_Temp, OneColorImage, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	}

	memcpy(InspectionArea_Temp, InspectionArea, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
}
//---------------------------------------------------------------------------
void CPB_Processing_Position(int mode)
{
	int InspectionOrStudy;

	InspectionOrStudy = mode;

	GettingThreeDPositionInformationForLaserComplexer(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0x00);

	if (InspectData.CoreProcessingMode[CPB_CORE_NUMBER] == SPLIT_PROCESSING_MODE_SUB)
	{
		// sub core의 경우 결과 반영 없음
		return;
	}
	/*
	int isDefect;
	int InspectionOrStudy;
	int InspectionKind;
	int tempIndex;

	InspectionOrStudy = INSPECTION_MODE;

	GettingThreeDPositionInformationForLaserComplexer(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0x00);

	if (InspectData.CoreProcessingMode[CPB_CORE_NUMBER] == SPLIT_PROCESSING_MODE_SUB)
	{
	// sub core의 경우 결과 반영 없음
	return;
	}

	DefectSW = 1;

	isDefect = DefectSW;
	DefectData_CPB.IsDefectA = ('N' << 8) + 'G';
	DefectData_CPB.IsDefectB = ('G' << 8) + 'N';
	DefectData_CPB.PrintIsSW = 0;
	DefectData_CPB.PrintType = -1;
	DefectData_CPB.ThickErrorSW = 0;
	DefectData_CPB.Front_Rear = 0;

	DefectInformation.cameraIndex = CurrentGlobalCamIndex + 1;
	DefectInformation.defectPositionStartX = ThreeDPositionInfo_CPB.TabletRotationAngle;
	DefectInformation.defectPositionEndX = ThreeDPositionInfo_CPB.TabletCenterX;
	DefectInformation.defectPositionStartY = ThreeDPositionInfo_CPB.TabletCenterY;
	DefectInformation.defectPositionEndY = 0;
	DefectInformation.size = ThreeDPositionInfo_CPB.TabletRotationAngle + ThreeDPositionInfo_CPB.TabletCenterX + ThreeDPositionInfo_CPB.TabletCenterY;

	memcpy(ThreeDImage_Temp, ThreeD_Image, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	*/
}
//---------------------------------------------------------------------------
void CPB_Processing_Inspection()
{
	int isDefect;
	int InspectionOrStudy;
	int InspectionKind;

	InspectionOrStudy = INSPECTION_MODE;

	if ((CurrentGlobalCamIndex + 1) == SD1_2D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_FRONT_FACE_CAMERA_INDEX)
	{
		InspectionKind = FRONT_FACE;
		ProcessingStartForFrontFace(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_3D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_3D_FRONT_FACE_CAMERA_INDEX)
	{
		InspectionKind = FRONT_FACE_3D;
		ProcessingStartForFrontFace_3D(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0x00);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_2D_SIDE_FACE_P45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_SIDE_FACE_P45_CAMERA_INDEX ||
	         (CurrentGlobalCamIndex + 1) == SD1_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_OTHER_SIDE_FACE_P45_CAMERA_INDEX)
	{
		InspectionKind = SIDE_FACE_P45;
		ProcessingStartForSideFace_P45(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_2D_SIDE_FACE_00_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_SIDE_FACE_00_CAMERA_INDEX ||
	         (CurrentGlobalCamIndex + 1) == SD1_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_OTHER_SIDE_FACE_00_CAMERA_INDEX)
	{
		InspectionKind = SIDE_FACE_0;
		ProcessingStartForSideFace_0(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}
	else if ((CurrentGlobalCamIndex + 1) == SD1_2D_SIDE_FACE_M45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_SIDE_FACE_M45_CAMERA_INDEX ||
	         (CurrentGlobalCamIndex + 1) == SD1_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_OTHER_SIDE_FACE_M45_CAMERA_INDEX)
	{
		InspectionKind = SIDE_FACE_M45;
		ProcessingStartForSideFace_M45(InspectionOrStudy, CurrentGlobalCamIndex + 1, 0);
	}

	if (InspectData.CoreProcessingMode[CPB_CORE_NUMBER] == SPLIT_PROCESSING_MODE_SUB)
	{
		// sub core의 경우 결과 반영 없음
		return;
	}

	if (TabletCharacter.kind == SUGARCOATING)
	{
		if (InspectionKind == SIDE_FACE_P45 || InspectionKind == SIDE_FACE_0 || InspectionKind == SIDE_FACE_M45)
		{
			memset(ThreeDImage_Temp, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memset(InspectionArea_Temp, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memset(ThreeDImage_Temp, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memset(InspectionArea_Temp, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		}
	}

	if ((CurrentGlobalCamIndex + 1) == SD1_2D_FRONT_FACE_CAMERA_INDEX && TabletCharacter.discriminationDisplay_kind == PRINT)
	{
		DefectData_CPB.PrintMatchingResult_PrintBrightness = PrintMarkingInformation.PrintBrightness;
		DefectData_CPB.PrintMatchingResult_PrintTheta = PrintMarkingInformation.theta;
		DefectData_CPB.PrintMatchingResult_PrintX = PrintMarkingInformation.x;
		DefectData_CPB.PrintMatchingResult_PrintY = PrintMarkingInformation.y;
	}
	else
	{
		DefectData_CPB.PrintMatchingResult_PrintBrightness = 0;
		DefectData_CPB.PrintMatchingResult_PrintTheta = 0;
		DefectData_CPB.PrintMatchingResult_PrintX = 0;
		DefectData_CPB.PrintMatchingResult_PrintY = 0;
	}

	isDefect = DefectSW;
	if (isDefect == 0)
	{
		DefectData_CPB.IsDefectA = ('O' << 8) + 'K';
		DefectData_CPB.IsDefectB = ('K' << 8) + 'O';

		if ((CurrentGlobalCamIndex + 1) == SD1_2D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_FRONT_FACE_CAMERA_INDEX)
		{
			DefectData_CPB.PrintIsSW = PrintIsSW;
			DefectData_CPB.PrintType = CurrentPrintType;
		}
		else if ((CurrentGlobalCamIndex + 1) == SD1_3D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_3D_FRONT_FACE_CAMERA_INDEX)
		{
			if (TabletCharacter.discriminationDisplay_kind == STAMP) // 음각, 양각
			{
				DefectData_CPB.PrintIsSW = PrintIsSW;
				DefectData_CPB.PrintType = CurrentPrintType;
			}
			else
			{
				DefectData_CPB.PrintIsSW = 0;
				DefectData_CPB.PrintType = -1;
			}
		}
		else
		{
			DefectData_CPB.PrintIsSW = 0;
			DefectData_CPB.PrintType = -1;
		}
	}
	else if (isDefect == 1)
	{
		DefectData_CPB.IsDefectA = ('N' << 8) + 'G';
		DefectData_CPB.IsDefectB = ('G' << 8) + 'N';

		if ((CurrentGlobalCamIndex + 1) == SD1_2D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_FRONT_FACE_CAMERA_INDEX)
		{
			DefectData_CPB.PrintIsSW = PrintIsSW;
			DefectData_CPB.PrintType = CurrentPrintType;
		}
		else if ((CurrentGlobalCamIndex + 1) == SD1_3D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_3D_FRONT_FACE_CAMERA_INDEX)
		{
			if (TabletCharacter.discriminationDisplay_kind == STAMP) // 음각, 양각
			{
				DefectData_CPB.PrintIsSW = PrintIsSW;
				DefectData_CPB.PrintType = CurrentPrintType;
			}
			else
			{
				DefectData_CPB.PrintIsSW = 0;
				DefectData_CPB.PrintType = -1;
			}
		}
		else
		{
			DefectData_CPB.PrintIsSW = 0;
			DefectData_CPB.PrintType = -1;
		}

		if (InspectionKind == FRONT_FACE_3D)
		{
			memcpy(ThreeDImage_Temp, ThreeD_Image, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memcpy(InspectionArea_Temp, InspectionArea, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		}
		else
		{
			memcpy(ThreeDImage_Temp, OneColorImage, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memcpy(InspectionArea_Temp, InspectionArea, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		}
	}
	else
	{
		DefectData_CPB.IsDefectA = ('U' << 8) + 'I';
		DefectData_CPB.IsDefectB = ('I' << 8) + 'U';

		if ((CurrentGlobalCamIndex + 1) == SD1_2D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_2D_FRONT_FACE_CAMERA_INDEX)
		{
			DefectData_CPB.PrintIsSW = PrintIsSW;
			DefectData_CPB.PrintType = CurrentPrintType;
		}
		else if ((CurrentGlobalCamIndex + 1) == SD1_3D_FRONT_FACE_CAMERA_INDEX || (CurrentGlobalCamIndex + 1) == SD2_3D_FRONT_FACE_CAMERA_INDEX)
		{
			if (TabletCharacter.discriminationDisplay_kind == STAMP) // 음각, 양각
			{
				DefectData_CPB.PrintIsSW = PrintIsSW;
				DefectData_CPB.PrintType = CurrentPrintType;
			}
			else
			{
				DefectData_CPB.PrintIsSW = 0;
				DefectData_CPB.PrintType = -1;
			}
		}
		else
		{
			DefectData_CPB.PrintIsSW = 0;
			DefectData_CPB.PrintType = -1;
		}

		if (isDefect == 2)
		{
			DefectData_CPB.EvalValue = 0;
		}
		else if (isDefect == 3)
		{
			DefectData_CPB.EvalValue = 1;
		}
		else if (isDefect == 4)
		{
			DefectData_CPB.EvalValue = 2;
		}
		else if (isDefect == 5)
		{
			DefectData_CPB.EvalValue = 3;
		}
		else
		{
			DefectData_CPB.EvalValue = 3;
		}

		if (InspectionKind == FRONT_FACE_3D)
		{
			memcpy(ThreeDImage_Temp, ThreeD_Image, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memcpy(InspectionArea_Temp, InspectionArea, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		}
		else
		{
			memcpy(ThreeDImage_Temp, OneColorImage, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			memcpy(InspectionArea_Temp, InspectionArea, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		}
	}

	DefectData_CPB.ThickErrorSW = ThickErrorSW;
	DefectData_CPB.Front_Rear = Front_Rear;
}
//---------------------------------------------------------------------------

void CPB_Processing_Inspection_TPB(void)
{
	DefectData_CPB.TPBInsDefect = 0;
	ProcessingStartForTPBImage(InspectData_TPB.TabletWidth, InspectData_TPB.TabletLength, InspectData_TPB.WhiteBalance[0], InspectData_TPB.WhiteBalance[1], InspectData_TPB.WhiteBalance[2],
	                           InspectData_TPB.InsAreaLeft, InspectData_TPB.InsAreaRight, InspectData_TPB.InsAreaTop, InspectData_TPB.InsAreaBottom , InspectData_TPB.Threshold);
	if (DefectSW == 4)
	{
		DefectData_CPB.TPBInsDefect = 1;
	}

	DefectData_CPB.IsDefectA = ('O' << 8) + 'K';
	DefectData_CPB.IsDefectB = ('K' << 8) + 'O';
}

//---------------------------------------------------------------------------
void InitialImageBuffer()
{
	memset(ColorSourceImage, 0, HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT * 3);
	memset(BayerImage, 0, HD_IMAGE_WIDTH * HD_IMAGE_HEIGHT);
	memset(OneColorImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);

	memset(MeanOneColorImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(ShapeBinaryImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(ShapeBinaryImageForPrintArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(GradientImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);

	memset(InspectionArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(realPrintMaskingArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(colorMaskingArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(BrightPixelNeighborPrint, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(DarkPixelNeighborPrint, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(DarkPixelNeighborPrint2, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(tShellInspectionArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(PlanariztionThreeDEdgeImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(TempImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(ThreeD_Image, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(AdjustThreeD_Data, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(ThreeD_Data, 0, HALF_MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(RotationThreeDImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(DentedArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(PrintLabelArea, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
	memset(RotationEdgeImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT * 2);
	memset(LabelImage_Virtual, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT * 2);
}
//---------------------------------------------------------------------------
void GettingThreeDPositionInformationForLaserComplexer(int processingMode, int cameraIndex, int option)
{
	int AlignedTabletSW;
	int MultiCoreInspectionIndicator = GETTING_POSITION_INDICATOR_FORBIDDEN; // 접근 불가
	int tempX, tempY;

#ifdef PC_SIM

	CPB_CORE_NUMBER = 0;
	memset(&InspectData, 0, sizeof(TInspectData));
	MultiCoreInspectionIndicator = GETTING_POSITION_INDICATOR_MAIN_ACCESS; // main process
	for (int coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
	{
		InspectData.CoreProcessingMode[coreIndex] = 0;
	}

#else

	if (InspectData.CoreProcessingMode[CPB_CORE_NUMBER] == SPLIT_PROCESSING_MODE_MAIN || InspectData.CoreProcessingMode[CPB_CORE_NUMBER] == SPLIT_PROCESSING_MODE_NONE)
	{
		MultiCoreInspectionIndicator = GETTING_POSITION_INDICATOR_MAIN_ACCESS; // main process
	}
	else
	{
		MultiCoreInspectionIndicator = GETTING_POSITION_INDICATOR_SUB_ACCESS; // sub process
	}

#endif

	threeDminX = threeDmaxX = threeDminY = threeDmaxY = 0;

	if (MultiCoreInspectionIndicator == GETTING_POSITION_INDICATOR_MAIN_ACCESS)
	{
		ProcessingModeGlobal = processingMode;
		DefectSW = 0;
		PrintIsSW = 0;
		PrintMatchingResult.dataNumberWithMaxValue = -1; // 초기값

		if (processingMode == STUDY_MODE || processingMode == INSPECTION_MODE)
		{
			Analysis3DImageForLaserComplexer(cameraIndex, (option & 0x0F));

			memset(&ThreeDPositionInfo_CPB, 0, sizeof(TThreeDPositionInfo));

			if (DefectSW)
			{
				ThreeDPositionInfo_CPB.TabletCenterX = 0xFFFF;
				ThreeDPositionInfo_CPB.TabletCenterY = 0xFFFF;
				ThreeDPositionInfo_CPB.TabletRotationAngle = 0;
				ThreeDPositionInfo_CPB.TabletHorizonalLength = 0;
				ThreeDPositionInfo_CPB.TabletVerticalLength = 0;
			}
			else
			{
				if (AdjustTabletCenterInfo[0] && AdjustTabletCenterInfo[1])
				{
					if (cameraIndex == SD1_3D_FRONT_FACE_CAMERA_INDEX)
					{
						ThreeDPositionInfo_CPB.TabletCenterX = (short)(TabletCharacter.Disk1ThreeDImageCenterYForLaser - AdjustTabletCenterInfo[1]);
						ThreeDPositionInfo_CPB.TabletCenterY = (short)(TabletCharacter.Disk1ThreeDImageCenterXForLaser - AdjustTabletCenterInfo[0]); // 절대 좌표를 기준으로 센터값의 차이를 전달한다.
						//ThreeDPositionInfo_CPB.TabletCenterY = TabletCharacter.Disk1ThreeDImageLengthForLaser / 2 - (AdjustTabletCenterInfo[0] - threeDminX); // 정제의 첫픽셀을 기준으로 예상 센터값(평균 길이의 1/2)과 계산값의 차이를 전달한다.
						
						ThreeDPositionInfo_CPB.TabletCenterX = (short)(-ThreeDPositionInfo_CPB.TabletCenterX);
						ThreeDPositionInfo_CPB.TabletCenterY = (short)(-ThreeDPositionInfo_CPB.TabletCenterY);
					}
					else
					{
						ThreeDPositionInfo_CPB.TabletCenterX = (short)(TabletCharacter.Disk2ThreeDImageCenterYForLaser - AdjustTabletCenterInfo[1]);
						ThreeDPositionInfo_CPB.TabletCenterY = (short)(TabletCharacter.Disk2ThreeDImageCenterXForLaser - AdjustTabletCenterInfo[0]);
						//ThreeDPositionInfo_CPB.TabletCenterY = TabletCharacter.Disk2ThreeDImageLengthForLaser / 2 - (AdjustTabletCenterInfo[0] - threeDminX);
						
						ThreeDPositionInfo_CPB.TabletCenterX = (short)(-ThreeDPositionInfo_CPB.TabletCenterX);
						ThreeDPositionInfo_CPB.TabletCenterY = (short)(-ThreeDPositionInfo_CPB.TabletCenterY);
					}
				}
				else
				{
					if (cameraIndex == SD1_3D_FRONT_FACE_CAMERA_INDEX)
					{
						ThreeDPositionInfo_CPB.TabletCenterX = (short)(TabletCharacter.Disk1ThreeDImageCenterYForLaser - ProtoTabletCenterY);
						ThreeDPositionInfo_CPB.TabletCenterY = (short)(TabletCharacter.Disk1ThreeDImageCenterXForLaser - ProtoTabletCenterX);
						//ThreeDPositionInfo_CPB.TabletCenterY = TabletCharacter.Disk1ThreeDImageLengthForLaser / 2 - (ProtoTabletCenterX - threeDminX);
						
						ThreeDPositionInfo_CPB.TabletCenterX = (-ThreeDPositionInfo_CPB.TabletCenterX);
						ThreeDPositionInfo_CPB.TabletCenterY = (-ThreeDPositionInfo_CPB.TabletCenterY);
					}
					else
					{
						ThreeDPositionInfo_CPB.TabletCenterX = (short)(TabletCharacter.Disk2ThreeDImageCenterYForLaser - ProtoTabletCenterY);
						ThreeDPositionInfo_CPB.TabletCenterY = (short)(TabletCharacter.Disk2ThreeDImageCenterXForLaser - ProtoTabletCenterX);
						//ThreeDPositionInfo_CPB.TabletCenterY = TabletCharacter.Disk2ThreeDImageLengthForLaser / 2 - (ProtoTabletCenterX - threeDminX);
						
						ThreeDPositionInfo_CPB.TabletCenterX = (-ThreeDPositionInfo_CPB.TabletCenterX);
						ThreeDPositionInfo_CPB.TabletCenterY = (-ThreeDPositionInfo_CPB.TabletCenterY);
					}
				}

				tempX = ThreeDPositionInfo_CPB.TabletCenterY;
				tempY = ThreeDPositionInfo_CPB.TabletCenterX;
				ThreeDPositionInfo_CPB.TabletCenterX = (short)tempX;
				ThreeDPositionInfo_CPB.TabletCenterY = (short)tempY;
				ThreeDPositionInfo_CPB.TabletCenterZ = (short)Center3DHeight;


				if(ThreeDPositionInfo_CPB.TabletCenterX == 0xFFFF && ThreeDPositionInfo_CPB.TabletCenterY == 0xFFFF)
				{
					ThreeDPositionInfo_CPB.TabletCenterX = 0;
					ThreeDPositionInfo_CPB.TabletCenterY = 0;
				}
				
				if(ThreeDPositionInfo_CPB.TabletCenterX == -1 && ThreeDPositionInfo_CPB.TabletCenterY == -1)
				{
					ThreeDPositionInfo_CPB.TabletCenterX = 0;
					ThreeDPositionInfo_CPB.TabletCenterY = 0;
				}				
				ThreeDPositionInfo_CPB.TabletHorizonalLength = (short)threeDTabletHorizonalLength;
				ThreeDPositionInfo_CPB.TabletVerticalLength = (short)threeDTabletVerticalLength;

				AlignedTabletSW = 0;
				if (TabletCharacter.shape == ETC)
				{
					if (TabletCharacter.length > TabletCharacter.width * 140 / 100)
					{
						AlignedTabletSW = 1;
					}
				}

				if (TabletCharacter.shape == OVAL || TabletCharacter.shape == OBLONG || AlignedTabletSW)
				{
					ThreeDPositionInfo_CPB.TabletRotationAngle = (short)ProtoTabletRotationAngle;
				}
				else if (TabletCharacter.shape == TRIANGLE)
				{
					ThreeDPositionInfo_CPB.TabletRotationAngle = (short)ProtoTabletRotationAngle;
				}
				else if (TabletCharacter.tabletDivisionLineInfo == BOTHSIDE_DIVISION_LINE)
				{
					ThreeDPositionInfo_CPB.TabletRotationAngle = (short)TabletSplitLineAngle;
				}
			}

			if (processingMode == STUDY_MODE)
			{
				memset(&TabletStudyData, 0, sizeof(TTabletStudyData));

				TabletStudyData.Print1_IsOrNotThreshold_ForCamera5 = 1000;
				TabletStudyData.Print2_IsOrNotThreshold_ForCamera5 = 1000;
				TabletStudyData.tabletMaxThickForFirstDisk = 100;
				TabletStudyData.tabletCenterThickForFirstDisk = 100;

				TabletStudyData.Print1_IsOrNotThreshold_ForCamera13 = 1000;
				TabletStudyData.Print2_IsOrNotThreshold_ForCamera13 = 1000;
				TabletStudyData.tabletMaxThickForSecondDisk = 100;
				TabletStudyData.tabletCenterThickForSecondDisk = 100;
			}
		}
	}
	else if (MultiCoreInspectionIndicator == GETTING_POSITION_INDICATOR_SUB_ACCESS)
	{
		ThreeDPositionMultiCoreProcessing();
	}
}
//---------------------------------------------------------------------------
void Analysis3DImageForLaserComplexer(int cameraIndex, int option)
{
	int x, y, x2, y2;
	int startX, endX, startY, endY;
	int tempAddress;
	int tempAddress2;
	int HalfStartX, HalfEndX;
	int HalfStartY, HalfEndY;
	int halfImageWidth, halfImageHeight;
	int maxImgSize;
	int maxLabelN;
	int tempCount;
	int upAvgValue;
	int upCount;
	int downAvgValue;
	int downCount;
	int value;
	int halfCenterX, halfCenterY;
	int smallSizeWidth;
	int sinV;
	int tempX, tempY;
	unsigned char *rotationThreeDImage;
		
	int maxValue;
	int tempValue;
	int rotationAngle;
	int limStX, limEdX, limStY, limEdY;	
	int binMinX, binMaxX, binMinY, binMaxY;
	int ActiveCoreCount;
	int coreIndex;
	int coreJobCount;
	int jobAssignedCount;
	int PrcessingCompleteSW;
	int jobStartPointer;
	int minY, maxY;
	int upperLimitY;
	int lowerLimitY;
	int lowerAvgHeight;
	int lowerAvgPosY;
	int upperAvgHeight;
	int upperAvgPosY;
	int leftAvgHeight;
	int leftAvgPosX;
	int rightAvgHeight;
	int rightAvgPosX;
	int edgeAvgHeight;
	int tempAngle;

	int upperPos[2];
	int lowerPos[2];
	int tempProtoTabletCenterHeight;

	int heightDiff;
	int dX, dY, dXH, dYH;
	int length;
	int tiltR;
	int adjustShiftPositionX, adjustShiftPositionY;
	int m, r;
	int tempCount1, tempCount2, tempCount3, tempCount4;
	int AlignedTabletSW;
	int ThreeDOutlineInfo[361];
	int angle;
	int angleRange;
	int AverageLength;
	int zeroAngle;
	
	
	int left;
	int right;
	int up;
	int down;
	int upleft;
	int upright;
	int downleft;
	int downright;
	int upValue;
	int downValue;
	int leftValue;
	int rightValue;
	int upleftValue;
	int downrightValue;
	int uprightValue;
	int downleftValue;
	int tempNeighborHeight[4];
	int n;
	int maxHeight;
	int tempHeight;
	int minDepth;
	int SymmetryAngle;
	int CheckPoint1, CheckPoint2, CheckPoint3;

	int SymmetryAxis;
	int sectionA, sectionB;
	int shiftAngle;
	int blankSW;
	int leftGrad;
	int rightGrad;
	int upGrad;
	int downGrad;
	int gradX, gradY;
	int TabletHeight;
	int errorHeightCount;
	int neighborSumColor;
	int range;
	int i, j;

	const int MIN_TABLET_SIZE = 50;

	startX = 4;
	endX = TabletSetupData.ImageCutEndX[cameraIndex - 1] - 4;
	startY = TabletSetupData.ImageCutStartY[cameraIndex - 1] + 4;
	endY = TabletSetupData.ImageCutEndY[cameraIndex - 1] - 4;

	if (startX < 0)
		startX = 1;
	if (endX > MAX_IMAGE_WIDTH)
		endX = MAX_IMAGE_WIDTH - 1;
	if (startY < 0)
		startY = 1;
	if (endY > MAX_IMAGE_HEIGHT)
		endY = MAX_IMAGE_HEIGHT - 1;

	HalfStartX = startX / 2;
	HalfEndX = endX / 2;
	HalfStartY = startY / 2;
	HalfEndY = endY / 2;

	smallSizeWidth = MAX_IMAGE_WIDTH / 2;

	if (option != 2)
	{
		memset(ThreeD_Data, 0, HALF_MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		Make_ThreeD_Data_From_Src(cameraIndex, 1); // ThreeD_Data에 값이 없는 경우 BayerImage에서 3D 이미지 추출부터 10이하 커트와 half 사이즈 복원까지 전부 처리 해준다. 뒤의 옵션 1을 넣어야 동시에 처리됨.
	}
	else
	{
		// ThreeD_Data에 값이 이미 들어있는 경우. 10이하 커트와 half 사이즈 복원만 해준다.
		// half 사이즈 복원
		memset(ThreeD_Image, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
		for (y = startY; y < endY; y++)
		{
			for (x = HalfStartX, x2 = HalfStartX * 2; x < HalfEndX; x++, x2 += 2)
			{
				tempAddress = HALF_MAX_IMAGE_WIDTH * y + x;
				tempAddress2 = MAX_IMAGE_WIDTH * y + x2; // 곱하기 1개 제거.

				value = ThreeD_Data[tempAddress];
				if (value >= 10) // 10미만 커트.
				{
					ThreeD_Image[tempAddress2 + 0] = value;
					ThreeD_Image[tempAddress2 + 1] = value;
				}
			}
		}
	}

	AlignedTabletSW = 0;
	if (TabletCharacter.shape == ETC)
	{
		if (TabletCharacter.length > TabletCharacter.width * 140 / 100)
		{
			AlignedTabletSW = 1;
		}
	}

	/*
	memcpy(OneColorImage, ThreeD_Image, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);

	// hole check
	for (y = startY; y < endY; y++)
	{
	  for (x = startX; x < endX; x++)
	  {
	    tempAddress = MAX_IMAGE_WIDTH * y + x;
	    if (OneColorImage[tempAddress] == 0)
	    {
	      neighborSumColor = tempCount = 0;

	      if(OneColorImage[tempAddress - 2])
	      {
	        neighborSumColor += OneColorImage[tempAddress - 2];
	        tempCount++;
	      }
	      else
	      {
	        continue; 
	      }

	      if(OneColorImage[tempAddress + 2])
	      {
	        neighborSumColor += OneColorImage[tempAddress + 2];
	        tempCount++;
	      }
	      else
	      {
	        continue; 
	      }

	      if(OneColorImage[tempAddress - 2 * MAX_IMAGE_WIDTH])
	      {
	        neighborSumColor += OneColorImage[tempAddress - 2 * MAX_IMAGE_WIDTH];
	        tempCount++;
	      }
	      else
	      {
	        continue; 
	      }

	      if(OneColorImage[tempAddress + 2 * MAX_IMAGE_WIDTH])
	      {
	        neighborSumColor += OneColorImage[tempAddress + 2 * MAX_IMAGE_WIDTH];
	        tempCount++;
	      }
	      else
	      {
	        continue; 
	      }

	      ThreeD_Image[tempAddress] = neighborSumColor / tempCount;
	    }
	  }
	}
	*/

	blankSW = 0;

	halfImageWidth = MAX_IMAGE_WIDTH / 2;
	halfImageHeight = MAX_IMAGE_HEIGHT / 2;
	maxImgSize = halfImageWidth * halfImageHeight;

	memset(HalfTempImage, 0, maxImgSize);
	memset(HalfLabelImage, 0, 2 * maxImgSize);

	for (y = startY, y2 = HalfStartY; y < endY; y += 2, ++y2) // x y를 각각 2로 나누던 것을 두가지 변수를 한번에 증가시켜서 속도 개선.
	{
		for (x = startX, x2 = HalfStartX; x < endX; x += 2, ++x2)
		{
			tempAddress = y2 * halfImageWidth + x2;

			HalfTempImage[tempAddress] = ThreeD_Image[MAX_IMAGE_WIDTH * y + x];
		}
	}

	maxLabelN = LabellingForTabletImage(HalfLabelImage, HalfTempImage, HalfStartX, HalfEndX, HalfStartY, HalfEndY, halfImageWidth, halfImageHeight);

	ProtoTabletCenterX = 0;
	ProtoTabletCenterY = 0;
	ProtoTabletCenterZ = 0;
	AdjustTabletCenterInfo[0] = AdjustTabletCenterInfo[1] = 0;

	Center3DHeight = 0;

	tempCount = 0;
	ProtoTabletRotationAngle = 0;
	TabletSplitLineAngle = 0;

	threeDTabletHorizonalLength = 0;
	threeDTabletVerticalLength = 0;

	rotationThreeDImage = HalfGradientImage;
	memset(HalfShrinkShapeBinaryImage, 0, (MAX_IMAGE_WIDTH / 2)*(MAX_IMAGE_HEIGHT / 2));

	if (ProcessingModeGlobal == INSPECTION_MODE && TabletGradeData.LIMA_ThreeD_Side_EraseLevel)
	{
#ifdef PC_SIM
		memset(OneColorImage, 0, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
#endif

		if (maxLabelN != 0)
		{
			for (y = startY, y2 = HalfStartY; y < endY; y += 2, ++y2)
			{
				for (x = startX, x2 = HalfStartX; x < endX; x += 2, ++x2)
				{
					tempAddress = halfImageWidth * y2 + x2;
					if (HalfLabelImage[tempAddress] == maxLabelN)
					{
						ProtoTabletCenterX += x;
						ProtoTabletCenterY += y;
						tempCount++;
					}
				}
			}

			if (tempCount)
			{
				ProtoTabletCenterX /= tempCount;
				ProtoTabletCenterY /= tempCount;
			}

			memset(ThreeDOutLineImage, 0, MAX_IMAGE_WIDTH*MAX_IMAGE_HEIGHT);
			for (y = startY, y2 = HalfStartY; y < endY; y += 2, ++y2)
			{
				for (x = startX, x2 = HalfStartX; x < endX; x += 2, ++x2)
				{
					if (x > 4 && x < MAX_IMAGE_WIDTH - 4 && y > 4 && y < MAX_IMAGE_HEIGHT - 4)
					{
						tempAddress = y * MAX_IMAGE_WIDTH + x;

						if (ThreeD_Image[tempAddress])
						{
							leftGrad = ThreeD_Image[tempAddress] - ThreeD_Image[tempAddress - 4];
							rightGrad = ThreeD_Image[tempAddress] - ThreeD_Image[tempAddress + 4];
							upGrad = ThreeD_Image[tempAddress] - ThreeD_Image[tempAddress - MAX_IMAGE_WIDTH * 4];
							downGrad = ThreeD_Image[tempAddress] - ThreeD_Image[tempAddress + MAX_IMAGE_WIDTH * 4];

							if (leftGrad < 0)
								leftGrad = 0;
							if (rightGrad < 0)
								rightGrad = 0;
							if (upGrad < 0)
								upGrad = 0;
							if (downGrad < 0)
								downGrad = 0;

							if (x < ProtoTabletCenterX)
							{
								gradX = leftGrad;
							}
							else
							{
								gradX = rightGrad;
							}

							if (y < ProtoTabletCenterY)
							{
								gradY = upGrad;
							}
							else
							{
								gradY = downGrad;
							}

							tempAddress2 = y2 * halfImageWidth + x2;

							ThreeDOutLineImage[tempAddress2] = max(gradX, gradY);
						}
					}
				}
			}

			for (y = startY, y2 = HalfStartY; y < endY; y += 2, ++y2)
			{
				for (x = startX, x2 = HalfStartX; x < endX; x += 2, ++x2)
				{
					tempAddress = y2 * halfImageWidth + x2;

					if (ThreeDOutLineImage[tempAddress] >= TabletGradeData.LIMA_ThreeD_Side_EraseLevel)
					{
						for (tempY = y - 1; tempY <= y + 1; tempY++)
						{
							for (tempX = x - 1; tempX <= x + 1; tempX++)
							{
								if (tempX >= 0 && tempX < MAX_IMAGE_WIDTH && tempY >= 0 && tempY < MAX_IMAGE_HEIGHT)
								{
									ThreeD_Image[tempY * MAX_IMAGE_WIDTH + tempX] = 0;
#ifdef PC_SIM

									OneColorImage[tempY * MAX_IMAGE_WIDTH + tempX] = 1;
#endif

								}
							}
						}
					}
				}
			}
		}
		else
		{
			blankSW = 1;
			goto THREED_IMAGE_ERROR;
		}

		memset(HalfTempImage, 0, maxImgSize);
		memset(HalfLabelImage, 0, 2 * maxImgSize);

		for (y = startY, y2 = HalfStartY; y < endY; y += 2, ++y2)
		{
			for (x = startX, x2 = HalfStartX; x < endX; x += 2, ++x2)
			{
				tempAddress = y2 * halfImageWidth + x2;

				HalfTempImage[tempAddress] = ThreeD_Image[MAX_IMAGE_WIDTH * y + x];
			}
		}

		maxLabelN = LabellingForTabletImage(HalfLabelImage, HalfTempImage, HalfStartX, HalfEndX, HalfStartY, HalfEndY, halfImageWidth, halfImageHeight);

		ProtoTabletCenterX = 0;
		ProtoTabletCenterY = 0;
		tempCount = 0;
	}

	if (maxLabelN != 0)
	{
		binMinX = MAX_IMAGE_WIDTH;
		binMaxX = 0;
		binMinY = MAX_IMAGE_HEIGHT;
		binMaxY = 0;

		for (y = startY, y2 = HalfStartY; y < endY; y += 2, ++y2)
		{
			for (x = startX, x2 = HalfStartX; x < endX; x += 2, ++x2)
			{
				tempAddress = halfImageWidth * y2 + x2;
				if (HalfLabelImage[tempAddress] == maxLabelN)
				{
					HalfShrinkShapeBinaryImage[tempAddress] = 1;

					ProtoTabletCenterX += x;
					ProtoTabletCenterY += y;
					ProtoTabletCenterZ += ThreeD_Image[MAX_IMAGE_WIDTH * y + x];
					tempCount++;

					if (binMinX > x)
					{
						binMinX = x;
					}

					if (binMaxX < x)
					{
						binMaxX = x;
					}

					if (binMinY > y)
					{
						binMinY = y;
					}

					if (binMaxY < y)
					{
						binMaxY = y;
					}
				}
				else if (HalfLabelImage[tempAddress])
				{
					ThreeD_Image[MAX_IMAGE_WIDTH * y + x] = 0;
					ThreeD_Image[MAX_IMAGE_WIDTH * y + x + 1] = 0;
					ThreeD_Image[MAX_IMAGE_WIDTH * (y + 1) + x] = 0;
					ThreeD_Image[MAX_IMAGE_WIDTH * (y + 1) + x + 1] = 0;
					HalfTempImage[tempAddress] = 0;
#ifdef PC_SIM
					OneColorImage[MAX_IMAGE_WIDTH * y + x] = 2;
					OneColorImage[MAX_IMAGE_WIDTH * y + x + 1] = 2;
					OneColorImage[MAX_IMAGE_WIDTH * (y + 1) + x] = 2;
					OneColorImage[MAX_IMAGE_WIDTH * (y + 1) + x + 1] = 2;
#endif
				}
			}
		}


		threeDminX = binMinX;
		threeDmaxX = binMaxX;
		threeDminY = binMinY;
		threeDmaxY = binMaxY;

		threeDTabletHorizonalLength = abs(binMinX - binMaxX);
		threeDTabletVerticalLength = abs(binMinY - binMaxY);

		if (ProcessingModeGlobal == INSPECTION_MODE && TabletGradeData.LIMA_ThreeD_MaxHeight)
		{
			errorHeightCount = 0;
			if (cameraIndex == SD1_3D_FRONT_FACE_CAMERA_INDEX)
			{
				TabletHeight = TabletStudyData.tabletMaxThickForFirstDisk;
			}
			else if (cameraIndex == SD2_3D_FRONT_FACE_CAMERA_INDEX)
			{
				TabletHeight = TabletStudyData.tabletMaxThickForSecondDisk;
			}

			TabletHeight += TabletGradeData.LIMA_ThreeD_MaxHeight;

			for (y = startY; y < endY; y++)
			{
				for (x = startX; x < endX; x++)
				{
					tempAddress = y * MAX_IMAGE_WIDTH + x;

					if (ThreeD_Image[tempAddress] >= TabletHeight)
					{
						errorHeightCount++;
#ifdef PC_SIM

						OneColorImage[tempAddress] = 2;
#endif

					}
				}
			}

			if (errorHeightCount > TabletGradeData.LIMA_ThreeD_OverHeightSize)
			{
				blankSW = 1;
				goto THREED_IMAGE_ERROR;
			}
		}


		if (tempCount > MIN_TABLET_SIZE)
		{
			ProtoTabletCenterX /= tempCount;
			ProtoTabletCenterY /= tempCount;
			ProtoTabletCenterZ /= tempCount;

			// tilting에 대한 center 좌표 보정
			// 이때 Y축 방향으로 위쪽이나 아래쪽은 정제의 옆면이 노출될 가능성이 있으므로 제외하고 중심선 부근의 양끝쪽만 체크한다.
			// 정제가 완전히 똑바로 놓여있을 때 정면의 테두리는 높이가 일정하다는 가정하에 계산한다.
			adjustShiftPositionX = adjustShiftPositionY = 0;
			upperLimitY = ProtoTabletCenterY - abs(binMinY - binMaxY) / 4;
			lowerLimitY = ProtoTabletCenterY + abs(binMinY - binMaxY) / 4;
			lowerAvgHeight = 0;
			lowerAvgPosY = 0;
			upperAvgHeight = 0;
			upperAvgPosY = 0;
			leftAvgHeight = 0;
			leftAvgPosX = 0;
			rightAvgHeight = 0;
			rightAvgPosX = 0;
			edgeAvgHeight = 0;

			tempCount = tempCount1 = tempCount2 = tempCount3 = tempCount4 = 0;
			for (y = upperLimitY; y < ProtoTabletCenterY; y += 2)			
			{
				for (x = binMinX; x < ProtoTabletCenterX; x += 2)
				{
					tempAddress = MAX_IMAGE_WIDTH * y + x;
					tempHeight = ThreeD_Image[tempAddress];
					if (tempHeight)
					{
						edgeAvgHeight += tempHeight;
						upperAvgHeight += tempHeight;
						upperAvgPosY += y;
						leftAvgHeight += tempHeight;
						leftAvgPosX += x;
						tempCount1++;
						tempCount++;
						break;
					}
				}

				for (x = binMaxX; x > ProtoTabletCenterX; x -= 2)
				{
					tempAddress = MAX_IMAGE_WIDTH * y + x;
					tempHeight = ThreeD_Image[tempAddress];
					if (tempHeight)
					{
						edgeAvgHeight += tempHeight;
						upperAvgHeight += tempHeight;
						upperAvgPosY += y;
						rightAvgHeight += tempHeight;
						rightAvgPosX += x;
						tempCount2++;
						tempCount++;
						break;
					}
				}
			}

			for (y = lowerLimitY; y > ProtoTabletCenterY; y -= 2)			
			{
				for (x = binMinX; x < ProtoTabletCenterX; x += 2)
				{
					tempAddress = MAX_IMAGE_WIDTH * y + x;
					tempHeight = ThreeD_Image[tempAddress];
					if (tempHeight)
					{
						edgeAvgHeight += tempHeight;
						lowerAvgHeight += tempHeight;
						lowerAvgPosY += y;
						leftAvgHeight += tempHeight;
						leftAvgPosX += x;
						tempCount3++;
						tempCount++;
						break;
					}
				}

				for (x = binMaxX; x > ProtoTabletCenterX; x -= 2)
				{
					tempAddress = MAX_IMAGE_WIDTH * y + x;
					tempHeight = ThreeD_Image[tempAddress];
					if (tempHeight)
					{
						edgeAvgHeight += tempHeight;
						lowerAvgHeight += tempHeight;
						lowerAvgPosY += y;
						rightAvgHeight += tempHeight;
						rightAvgPosX += x;
						tempCount4++;
						tempCount++;
						break;
					}
				}
			}

			if (tempCount)
			{
				edgeAvgHeight /= tempCount;
			}

			if (tempCount1 + tempCount2 > 0)
			{
				upperAvgHeight /= (tempCount1 + tempCount2);
				upperAvgPosY /= (tempCount1 + tempCount2);
			}

			if (tempCount3 + tempCount4 > 0)
			{
				lowerAvgHeight /= (tempCount3 + tempCount4);
				lowerAvgPosY /= (tempCount3 + tempCount4);
			}

			if (tempCount1 + tempCount3 > 0)
			{
				leftAvgHeight /= (tempCount1 + tempCount3);
				leftAvgPosX /= (tempCount1 + tempCount3);
			}

			if (tempCount2 + tempCount4 > 0)
			{
				rightAvgHeight /= (tempCount2 + tempCount4);
				rightAvgPosX /= (tempCount2 + tempCount4);
			}

			if (leftAvgPosX && rightAvgPosX && lowerAvgPosY && upperAvgPosY)
			{
				dX = leftAvgPosX - rightAvgPosX;
				dY = upperAvgPosY - lowerAvgPosY;
				dXH = leftAvgHeight - rightAvgHeight;
				dYH = upperAvgHeight - lowerAvgHeight;

				tempCount = tempProtoTabletCenterHeight = 0;
				for (y = ProtoTabletCenterY - 20; y <= ProtoTabletCenterY + 20; y += 4)			
				{
					for (x = ProtoTabletCenterX - 20; x <= ProtoTabletCenterX + 20; x += 4)
					{
						tempAddress = MAX_IMAGE_WIDTH * y + x;
						tempHeight = ThreeD_Image[tempAddress];
						if (tempHeight)
						{
							tempProtoTabletCenterHeight += tempHeight;
							tempCount++;
							break;
						}
					}
				}				

				if (tempCount)
				{
					tempProtoTabletCenterHeight /= tempCount;
					Center3DHeight = tempProtoTabletCenterHeight;
				}

				if (dX < 0 && abs(dXH) > 0) // 틸팅이 발생하는 경우
				{
					length = dX * dX + dXH * dXH;

					if (length >= 90000) // X축은 종종 이 값을 넘을 수 있다.
					{
						length /= 4; // SqrtData가 90000까지 밖에 없어서 스케일을 줄여줌. 제곱이므로 1/4
						dXH /= 2;
					}

					if (length < 90000)
					{
						length = SqrtData[length];
						sinV = 1280000 * dXH / length;

						if (sinV > 10000)
							sinV = 10000;
						else if (sinV < -10000)
							sinV = -10000;

						if (TabletCharacter.kind == SUGARCOATING)
						{
							// x2 : 삼각함수 array의 비율 조정, x1.2 : 실제 보정수치에 가중 적용
							if (sinV < 0)
								tiltR = ArcSinData2[-sinV] * 2;
							else
								tiltR = -ArcSinData2[sinV] * 2;
						}
						else
						{
							if (sinV < 0)
								tiltR = ArcSinData[-sinV] * 2;
							else
								tiltR = -ArcSinData[sinV] * 2;
						}

						if (tiltR < 0)
						{
							adjustShiftPositionX = -(tempProtoTabletCenterHeight - edgeAvgHeight) * SinData[-tiltR] / 1024;
						}
						else
						{
							adjustShiftPositionX = (tempProtoTabletCenterHeight - edgeAvgHeight) * SinData[tiltR] / 1024;
						}

					}
				}				

				if (dY < 0 && abs(dYH) > 0) // 틸팅이 발생하는 경우
				{
					length = dY * dY + dYH * dYH;
					
					if (length < 90000)
					{
						length = SqrtData[length];
						sinV = 1280000 * dYH / length;

						if (sinV > 10000)
							sinV = 10000;
						else if (sinV < -10000)
							sinV = -10000;

						if (TabletCharacter.kind == SUGARCOATING)
						{
							// x2 : 삼각함수 array의 비율 조정, x1.2 : 실제 보정수치에 가중 적용
							if (sinV < 0)
								tiltR = ArcSinData2[-sinV] * 2;
							else
								tiltR = -ArcSinData2[sinV] * 2;
						}
						else
						{
							if (sinV < 0)
								tiltR = ArcSinData[-sinV] * 2;
							else
								tiltR = -ArcSinData[sinV] * 2;
						}

						if (tiltR < 0)
						{
							adjustShiftPositionY = -(tempProtoTabletCenterHeight - edgeAvgHeight) * SinData[-tiltR] / 1024;
						}
						else
						{
							adjustShiftPositionY = (tempProtoTabletCenterHeight - edgeAvgHeight) * SinData[tiltR] / 1024;
						}

					}
				}
			}

			AdjustTabletCenterInfo[0] = ProtoTabletCenterX - adjustShiftPositionX;
			AdjustTabletCenterInfo[1] = ProtoTabletCenterY - adjustShiftPositionY;

			halfCenterX = ProtoTabletCenterX / 2;
			halfCenterY = ProtoTabletCenterY / 2;

			// 2020-12-11
			// 위 프로세스까지 약 6ms 소요
			// 검사 영역 크기에 따라 소요시간을 달라질 수 있음
			// test 이미지는 보통 사이즈의 정제
			// 많은 시간이 소요되는 것은 아니므로 분할처리를 적용하지 않는다
			// ref. 3D 센싱에서 레이저 마킹까지의 거리는 약 30mm ~ 40mm

			// 2021-02-09
			// 위 프로세스까지
			// 약 15ms 소요 (Oval / 18.24mm)
			// 약 10ms 소요 (Round / 7.2mm)
			// 분할처리에 대해서는 아직 적용 고려하지 않음

			if (TabletCharacter.shape == OVAL || TabletCharacter.shape == OBLONG || AlignedTabletSW)
			{
				//memcpy(rotationThreeDImage, HalfShrinkShapeBinaryImage, (MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)); // temp buffer
				memset(rotationThreeDImage, 0, (MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2));

				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = halfImageWidth * y + x;

						if (HalfShrinkShapeBinaryImage[tempAddress]) // 2 픽셀거리의 외곽부를 찾아서 마킹.
						{
							if (HalfShrinkShapeBinaryImage[tempAddress - 2] == 0 ||
							        HalfShrinkShapeBinaryImage[tempAddress + 2] == 0 ||
							        HalfShrinkShapeBinaryImage[tempAddress - 2 * halfImageWidth] == 0 ||
							        HalfShrinkShapeBinaryImage[tempAddress + 2 * halfImageWidth] == 0)
							{
								rotationThreeDImage[tempAddress] = 1;
							} 
						}
					}
				}

				for (angle = 0; angle < 361; angle++)
				{
					ThreeDOutlineInfo[angle] = -1;
				}

				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = HALF_IMAGE_WIDTH * y + x;
						if (rotationThreeDImage[tempAddress])
						{
							dX = x - halfCenterX;
							dY = y - halfCenterY;
							length = dX * dX + dY * dY;
							if (length < 90000)
							{
								length = SqrtData[length]; //sqrtdata는 128이 곱해 진 상태.
								sinV = 1280000 * dX / length;
								if (sinV > 10000)
									sinV = 10000;

								if (dX >= 0 && dY <= 0)
									angle = ArcSinData[sinV];
								else if (dX >= 0 && dY > 0)
									angle = 180 - ArcSinData[sinV];
								else if (dX < 0 && dY > 0)
									angle = 180 + ArcSinData[ -sinV];
								else
									angle = 360 - ArcSinData[ -sinV];

								if (angle >= 0 && angle < 360)
								{
									if (ThreeDOutlineInfo[angle] < length)
									{
										ThreeDOutlineInfo[angle] = length;  // 각도에 따른 길이를 목록에 저장.
									}
								}
							}
						}
					}
				}

				for (angle = 0; angle < 360; angle++)
				{
					if (ThreeDOutlineInfo[angle] == -1)
					{
						length = 0;
						tempCount = 0;
						for (tempAngle = angle - 6; tempAngle <= angle + 6; tempAngle += 2)
						{
							tempAddress = (tempAngle + 360) % 360;

							if (ThreeDOutlineInfo[tempAddress] > -1)
							{
								length += ThreeDOutlineInfo[tempAddress];
								tempCount++;
							}
						}

						if (tempCount)
						{
							ThreeDOutlineInfo[angle] = length / tempCount;  // 비어있는 각도에 대한 길이 값을 채워 넣음.
						}
					}
				}

				// 길이가 최대가되는 각도를 구함. (장축. 사실은 장축근방의 마주보는 꼭지점을 잇는 대각선이 구해진다)
				maxValue = 0;
				for (angle = 0; angle < 180; angle++)
				{
					SymmetryAngle = (angle + 180) % 360;
					if (ThreeDOutlineInfo[angle] > -1 && ThreeDOutlineInfo[SymmetryAngle] > -1)
					{
						length = ThreeDOutlineInfo[angle] + ThreeDOutlineInfo[SymmetryAngle];

						if (maxValue < length)
						{
							maxValue = length;
							SymmetryAxis = angle;
						}
					}
				}

				zeroAngle = 0;
				AverageLength = tempCount = 0;

				// 외곽선을 돌면서 중심점과의 평균거리를 구함.
				for (angle = 0; angle < 360; angle++)
				{
					if (ThreeDOutlineInfo[angle] > -1)
					{
						AverageLength += ThreeDOutlineInfo[angle];
						tempCount++;
					}
				}

				// 기준이 되는 zeroAngle을 정제의 모양에 따라 구함. 좌우 대칭을 이루는 기준축.
				sectionA = min((SymmetryAxis - 90 + 360) % 360, (90 + SymmetryAxis + 360) % 360);
				sectionB = max((SymmetryAxis - 90 + 360) % 360, (90 + SymmetryAxis + 360) % 360);

				shiftAngle = 90 - SymmetryAxis;

				if (tempCount)
				{
					AverageLength /= tempCount;

					tempAngle = tempCount = 0;
					for (angle = 0; angle < 360; angle++)
					{
						if (ThreeDOutlineInfo[angle] > AverageLength)
						{
							if (angle >= sectionA && angle < sectionB)
							{
								tempAngle += (shiftAngle + angle - 180 + 360) % 360;
							}
							else
							{
								tempAngle += (shiftAngle + angle + 360) % 360;
							}

							tempCount++;
						}
					}

					if (tempCount)
					{
						tempAngle /= tempCount;
						tempAngle = tempAngle - 90 - shiftAngle;

						zeroAngle = tempAngle * 2; // 720 degree scale
						zeroAngle = (zeroAngle + 720) % 720;
						zeroAngle = 720 - zeroAngle;
					}
				}

				// 2021-02-09
				// 위 프로세스까지
				// 약 17ms 소요 (Oval / 18.24mm)
				// 분할처리에 대해서는 아직 적용 고려하지 않음
				// 해당 테스트 정제 기준 분할처리되는 회전 로직에서 + 8ms 소요되는 것으로 예상됨(데이터 수집 + 회전)

				memset(rotationThreeDImage, 0, (MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2));

				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = halfImageWidth * y + x;

						if (HalfShrinkShapeBinaryImage[tempAddress])
						{
							if (HalfShrinkShapeBinaryImage[tempAddress - 10] == 0 ||
							        HalfShrinkShapeBinaryImage[tempAddress + 10] == 0 ||
							        HalfShrinkShapeBinaryImage[tempAddress - 10 * halfImageWidth] == 0 ||
							        HalfShrinkShapeBinaryImage[tempAddress + 10 * halfImageWidth] == 0) // 외곽부
							{
								rotationThreeDImage[tempAddress] = 1;
							}
						}
					}
				}

				upAvgValue = upCount = downAvgValue = downCount = 0;
				for (y = startY; y < endY; y += 2)
				{
					for (x = startX; x < endX; x += 2)
					{
						tempAddress = MAX_IMAGE_WIDTH * y + x;
						value = ThreeD_Image[tempAddress];
						if (value)
						{
							if (y < ProtoTabletCenterY)
							{
								upAvgValue += value;
								upCount++;
							}
							else if (y > ProtoTabletCenterY)
							{
								downAvgValue += value;
								downCount++;
							}
						}
					}
				}

				if (upCount)
				{
					upAvgValue /= upCount;
				}

				if (downCount)
				{
					downAvgValue /= downCount;
				}

				if (upAvgValue > downAvgValue) // 정제가 기울어진 각도에 따라 위쪽 또는 아래쪽 반을 무시하기 위한 범위.
				{
					limStY = halfCenterY;
					limEdY = HalfEndY;
				}
				else
				{
					limStY = HalfStartY;
					limEdY = halfCenterY;
				}

				limStX = halfCenterX - threeDTabletHorizonalLength / 4 - 10; // 정제의 왼쪽 끝에서 조금 더 왼쪽.
				if (limStX < HalfStartX)
					limStX = HalfStartX;
				limEdX = halfCenterX + threeDTabletHorizonalLength / 4 + 10;
				if (limEdX > HalfEndX)
					limEdX = HalfEndX;
			
				startY = HalfStartY;
				endY = HalfEndY;
				startX = HalfStartX;
				endX = HalfEndX;

				// standby shared processing
#ifdef TARGET_CPB
				// 정확히 변경된 부분만 덮어 쓸 때는 읽기 안해도 됨.
				//cacheInvaliDate_ddr3((char *)&SharedProcessingParamsForRotation, sizeof(TSharedProcessingParamsForRotation));
#endif
				// init processing variable
				SharedProcessingParamsForRotation.ImageStartX[SHARED_MEMORY_VALID_POINTER] = startX;
				SharedProcessingParamsForRotation.ImageStartY[SHARED_MEMORY_VALID_POINTER] = startY;
				SharedProcessingParamsForRotation.ImageEndX[SHARED_MEMORY_VALID_POINTER] = endX;
				SharedProcessingParamsForRotation.ImageEndY[SHARED_MEMORY_VALID_POINTER] = endY;
				SharedProcessingParamsForRotation.ImageWidth[SHARED_MEMORY_VALID_POINTER] = smallSizeWidth;
				SharedProcessingParamsForRotation.ImageCenterX[SHARED_MEMORY_VALID_POINTER] = halfCenterX;
				SharedProcessingParamsForRotation.ImageCenterY[SHARED_MEMORY_VALID_POINTER] = halfCenterY;
				SharedProcessingParamsForRotation.LimitStartX[SHARED_MEMORY_VALID_POINTER] = limStX;
				SharedProcessingParamsForRotation.LimitEndX[SHARED_MEMORY_VALID_POINTER] = limEdX;
				SharedProcessingParamsForRotation.LimitStartY[SHARED_MEMORY_VALID_POINTER] = limStY;
				SharedProcessingParamsForRotation.LimitEndY[SHARED_MEMORY_VALID_POINTER] = limEdY;
				SharedProcessingParamsForRotation.ProtoTabletAngle[SHARED_MEMORY_VALID_POINTER] = zeroAngle;
				// end init processing variable
#ifdef TARGET_CPB

				cacheWriteBack_ddr3((char *)&SharedProcessingParamsForRotation, sizeof(TSharedProcessingParamsForRotation));
#endif



#ifdef TARGET_CPB
				// 전체를 변경후 덮어 쓸 때는 읽기 안해도 됨.
				//cacheInvaliDate_ddr3((char *)SharedImageBuffer, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
#endif
				// set src data
				memcpy(SharedImageBuffer, rotationThreeDImage, (MAX_IMAGE_WIDTH / 2)*(MAX_IMAGE_HEIGHT / 2));

				// end set src data
#ifdef TARGET_CPB

				cacheWriteBack_ddr3((char *)SharedImageBuffer, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
#endif



#ifdef TARGET_CPB
				// 전체를 변경후 덮어 쓸 때는 읽기 안해도 됨.
				//cacheInvaliDate_ddr3((char *)SharedJobDistributionForRotation, sizeof(int) * MAX_PROCESSING_CORE_COUNT * CACHE_CONTROL_DUMMY_SIZE * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1));
#endif

				memset(SharedJobDistributionForRotation, 0, sizeof(int) * MAX_PROCESSING_CORE_COUNT * CACHE_CONTROL_DUMMY_SIZE * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1));

				// job distribution
				ActiveCoreCount = 0;
				for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
				{
					if (InspectData.CoreProcessingMode[coreIndex])
					{
						ActiveCoreCount++;
					}
				}

				if (ActiveCoreCount > 1)
				{
					// 2개 이상이 분할 프로세싱 이 enable 된 경우
					coreJobCount = (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1) / ActiveCoreCount;
					ActiveCoreCount = ActiveCoreCount - 1;

					jobStartPointer = -SHARED_PROCESSING_ROTATION_ANGLE;
					for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
					{
						if (InspectData.CoreProcessingMode[coreIndex])
						{
							jobAssignedCount = 0;
							for (r = jobStartPointer; r <= SHARED_PROCESSING_ROTATION_ANGLE; r++)
							{
								SharedJobDistributionForRotation[coreIndex * CACHE_CONTROL_DUMMY_SIZE][r + SHARED_PROCESSING_ROTATION_ANGLE] = 1;
								jobAssignedCount++;

								if (jobAssignedCount >= coreJobCount)
								{
									if (ActiveCoreCount)
									{
										jobStartPointer += jobAssignedCount;
										ActiveCoreCount--;
										break;
									}
								}
							}
						}
					}
				}
				else
				{
					for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
					{
						for (r = -SHARED_PROCESSING_ROTATION_ANGLE; r <= SHARED_PROCESSING_ROTATION_ANGLE; r++)
						{
							SharedJobDistributionForRotation[coreIndex * CACHE_CONTROL_DUMMY_SIZE][r + SHARED_PROCESSING_ROTATION_ANGLE] = 1;
						}
					}
				}
				// end job distribution
#ifdef TARGET_CPB
				cacheWriteBack_ddr3((char *)SharedJobDistributionForRotation, sizeof(int) * MAX_PROCESSING_CORE_COUNT * CACHE_CONTROL_DUMMY_SIZE * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1));
#endif



#ifdef TARGET_CPB
				// 정확히 변경된 부분만 덮어 쓸 때는 읽기 안해도 됨.
				//cacheInvaliDate_ddr3((char *)SharedProcessingResultForRotation, sizeof(int) * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1) * CACHE_CONTROL_DUMMY_SIZE);
#endif
				// init result
				memset(SharedProcessingResultForRotation, 0, sizeof(int) * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1) * CACHE_CONTROL_DUMMY_SIZE);
				// end init result
#ifdef TARGET_CPB

				cacheWriteBack_ddr3((char *)SharedProcessingResultForRotation, sizeof(int) * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1) * CACHE_CONTROL_DUMMY_SIZE);
#endif



#ifdef TARGET_CPB

				// for set subcore idle status
				cacheInvaliDate_ddr3((char *)SubcoreProcessingActiveSW, MAX_PROCESSING_CORE_COUNT * sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
#endif
				// set subcore processing start
				for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
				{
					if (InspectData.CoreProcessingMode[coreIndex] == SPLIT_PROCESSING_MODE_SUB)
					{
						SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * coreIndex] = 1; // 서브 코어에 대한 정보만 덮어씀.
					}
				}
				// end set subcore processing start
#ifdef TARGET_CPB
				cacheWriteBack_ddr3((char *)SubcoreProcessingActiveSW, MAX_PROCESSING_CORE_COUNT * sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
#endif
				// end standby

				// processing start
				CalculateRotataionResultWithMultiCore(startX, endX, startY, endY, smallSizeWidth, halfCenterX, halfCenterY, limStX, limEdX, limStY, limEdY, zeroAngle);

#ifdef TARGET_CPB
				while (1)
				{
					// wait sub core result
					cacheInvaliDate_ddr3((char *)SubcoreProcessingActiveSW, MAX_PROCESSING_CORE_COUNT * sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
					PrcessingCompleteSW = 1;

					for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
					{
						if (InspectData.CoreProcessingMode[coreIndex] == SPLIT_PROCESSING_MODE_SUB)
						{
							if (SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * coreIndex] == 1)
							{
								PrcessingCompleteSW = 0;
								break;
							}
						}
					}

					if (PrcessingCompleteSW)
						break;
				}

				cacheInvaliDate_ddr3((char *)SharedProcessingResultForRotation, sizeof(int) * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1) * CACHE_CONTROL_DUMMY_SIZE);
#endif

				rotationAngle = maxValue = 0;
				for (r = -SHARED_PROCESSING_ROTATION_ANGLE; r <= SHARED_PROCESSING_ROTATION_ANGLE; r += 4)
				{
					tempValue = SharedProcessingResultForRotation[(r + SHARED_PROCESSING_ROTATION_ANGLE) * CACHE_CONTROL_DUMMY_SIZE];
					if (maxValue < tempValue)
					{
						maxValue = tempValue;
						rotationAngle = zeroAngle + r;
					}
				}

				rotationAngle = (rotationAngle + 720) % 720;
				rotationAngle = (720 - rotationAngle) / 2;

				// 90도를 넘어가면 180도 뒤집어서 글자가 위로 가게한다.
				rotationAngle = rotationAngle % 180;
				if (rotationAngle > 90)
				{
					rotationAngle = 360 - (180 - rotationAngle);
				}

				ProtoTabletRotationAngle = rotationAngle;
			}
			else if (TabletCharacter.shape == TRIANGLE)
			{
				memcpy(rotationThreeDImage, HalfShrinkShapeBinaryImage, (MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2)); // temp buffer
				memset(HalfShrinkShapeBinaryImage, 0, (MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2));

				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = halfImageWidth * y + x;

						if (rotationThreeDImage[tempAddress])
						{
							if (rotationThreeDImage[tempAddress - 2] == 0 ||
							        rotationThreeDImage[tempAddress + 2] == 0 ||
							        rotationThreeDImage[tempAddress - 2 * halfImageWidth] == 0 ||
							        rotationThreeDImage[tempAddress + 2 * halfImageWidth] == 0) // 외곽부
							{
								HalfShrinkShapeBinaryImage[tempAddress] = 1;
							}
						}
					}
				}

				for (angle = 0; angle < 361; angle++)
				{
					ThreeDOutlineInfo[angle] = -1;
				}

				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = HALF_IMAGE_WIDTH * y + x;
						if (HalfShrinkShapeBinaryImage[tempAddress])
						{
							dX = x - halfCenterX;
							dY = y - halfCenterY;
							length = dX * dX + dY * dY;
							if (length < 90000)
							{
								length = SqrtData[length]; //sqrtdata는 128이 곱해 진 상태.
								sinV = 1280000 * dX / length;
								if (sinV > 10000)
									sinV = 10000;

								if (dX >= 0 && dY <= 0)
									angle = ArcSinData[sinV];
								else if (dX >= 0 && dY > 0)
									angle = 180 - ArcSinData[sinV];
								else if (dX < 0 && dY > 0)
									angle = 180 + ArcSinData[ -sinV];
								else
									angle = 360 - ArcSinData[ -sinV];

								if (angle >= 0 && angle < 360)
								{
									if (ThreeDOutlineInfo[angle] < length)
									{
										ThreeDOutlineInfo[angle] = length;
									}
								}
							}
						}
					}
				}

				for (angle = 0; angle < 360; angle++)
				{
					if (ThreeDOutlineInfo[angle] == -1)
					{
						length = 0;
						tempCount = 0;
						for (tempAngle = angle - 6; tempAngle <= angle + 6; tempAngle += 2)
						{
							tempAddress = (tempAngle + 360) % 360;

							if (ThreeDOutlineInfo[tempAddress] > -1)
							{
								length += ThreeDOutlineInfo[tempAddress];
								tempCount++;
							}
						}

						if (tempCount)
						{
							ThreeDOutlineInfo[angle] = length / tempCount;
						}
					}
				}

				maxValue = 0;
				for (angle = 0; angle < 120; angle++)
				{
					length = 0;
					for (range = -10; range <= 10; range += 5)
					{
						CheckPoint1 = ((angle + 0 + range) + 360) % 360;
						CheckPoint2 = ((angle + 120 + range) + 360) % 360;
						CheckPoint3 = ((angle + 240 + range) + 360) % 360;

						if (ThreeDOutlineInfo[CheckPoint1] > -1 && ThreeDOutlineInfo[CheckPoint2] > -1 && ThreeDOutlineInfo[CheckPoint3] > -1)
						{
							length += ThreeDOutlineInfo[CheckPoint1] + ThreeDOutlineInfo[CheckPoint2] + ThreeDOutlineInfo[CheckPoint3];
						}
					}

					if (maxValue < length)
					{
						maxValue = length;
						SymmetryAxis = angle;
					}
				}

				rotationAngle = SymmetryAxis;
				if (rotationAngle > 60)
				{
					rotationAngle = 360 - (120 - rotationAngle);
				}

				ProtoTabletRotationAngle = (rotationAngle + 180) % 360;
			}
			else if (TabletCharacter.tabletDivisionLineInfo == BOTHSIDE_DIVISION_LINE)
			{
				memset(HalfShrinkShapeBinaryImage, 0, (MAX_IMAGE_WIDTH / 2) * (MAX_IMAGE_HEIGHT / 2));

				for (length = 8; length <= 16; length += 8)
				{
					up = -halfImageWidth * length;
					down = halfImageWidth * length;
					left = -1 * length;
					right = 1 * length;
					upleft = ( -halfImageWidth - 1) * length;
					upright = ( -halfImageWidth + 1) * length;
					downleft = (halfImageWidth - 1) * length;
					downright = (halfImageWidth + 1) * length;

					minDepth = 2;

					for (y = HalfStartY; y < HalfEndY; y++)
					{
						for (x = HalfStartX; x < HalfEndX; x++)
						{
							tempAddress = halfImageWidth * y + x;

							if (HalfTempImage[tempAddress])
							{
								// 외곽부 필터링
								if (HalfTempImage[tempAddress - 4] &&
								        HalfTempImage[tempAddress + 4] &&
								        HalfTempImage[tempAddress - 4 * halfImageWidth] &&
								        HalfTempImage[tempAddress + 4 * halfImageWidth])
								{
									for (n = 0; n < 4; n++)
									{
										tempNeighborHeight[n] = 0;
									}

									tempAddress2 = tempAddress + up;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										upValue = HalfTempImage[tempAddress + up];
									else
										upValue = 0;

									tempAddress2 = tempAddress + down;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										downValue = HalfTempImage[tempAddress + down];
									else
										downValue = 0;

									tempAddress2 = tempAddress + left;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										leftValue = HalfTempImage[tempAddress + left];
									else
										leftValue = 0;

									tempAddress2 = tempAddress + right;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										rightValue = HalfTempImage[tempAddress + right];
									else
										rightValue = 0;

									tempAddress2 = tempAddress + upleft;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										upleftValue = HalfTempImage[tempAddress + upleft];
									else
										upleftValue = 0;

									tempAddress2 = tempAddress + downright;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										downrightValue = HalfTempImage[tempAddress + downright];
									else
										downrightValue = 0;

									tempAddress2 = tempAddress + upright;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										uprightValue = HalfTempImage[tempAddress + upright];
									else
										uprightValue = 0;

									tempAddress2 = tempAddress + downleft;
									if (tempAddress2 > halfImageWidth * 4 + 4 && tempAddress2 < halfImageWidth * (halfImageHeight - 4) + halfImageWidth - 4)
										downleftValue = HalfTempImage[tempAddress + downleft];
									else
										downleftValue = 0;

									if (upValue && downValue)
									{
										tempNeighborHeight[0] = upValue + downValue;
									}
									if (leftValue && rightValue)
									{
										tempNeighborHeight[1] = leftValue + rightValue;
									}
									if (upleftValue && downrightValue)
									{
										tempNeighborHeight[2] = upleftValue + downrightValue;
									}
									if (uprightValue && downleftValue)
									{
										tempNeighborHeight[3] = uprightValue + downleftValue;
									}

									maxHeight = 0;
									for (n = 0; n < 4; n++)
									{
										if (tempNeighborHeight[n] / 2 > maxHeight)
										{
											maxHeight = tempNeighborHeight[n] / 2;
										}
									}

									if (maxHeight)
									{
										tempHeight = maxHeight - HalfTempImage[tempAddress];
										if (tempHeight >= HalfShrinkShapeBinaryImage[tempAddress] + minDepth)
										{
											HalfShrinkShapeBinaryImage[tempAddress] = tempHeight;
										}
									}
								}
							}
						}
					}
				}

				memset(HalfLabelImage, 0, 2 * maxImgSize);
				maxLabelN = LabellingForTabletImage(HalfLabelImage, HalfShrinkShapeBinaryImage, HalfStartX, HalfEndX, HalfStartY, HalfEndY, halfImageWidth, halfImageHeight);
				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = halfImageWidth * y + x;

						if (HalfLabelImage[tempAddress] != maxLabelN)
						{
							HalfShrinkShapeBinaryImage[tempAddress] = 0;
						}
					}
				}

				for (angle = 0; angle < 361; angle++)
				{
					ThreeDOutlineInfo[angle] = -1;
				}

				AverageLength = tempCount = 0;
				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = HALF_IMAGE_WIDTH * y + x;
						tempHeight = HalfShrinkShapeBinaryImage[tempAddress];
						if (tempHeight)
						{
							dX = x - halfCenterX;
							dY = y - halfCenterY;
							length = dX * dX + dY * dY;
							if (length < 90000)
							{
								length = SqrtData[length]; //sqrtdata는 128이 곱해 진 상태.
								sinV = 1280000 * dX / length;
								if (sinV > 10000)
									sinV = 10000;

								if (dX >= 0 && dY <= 0)
									angle = ArcSinData[sinV];
								else if (dX >= 0 && dY > 0)
									angle = 180 - ArcSinData[sinV];
								else if (dX < 0 && dY > 0)
									angle = 180 + ArcSinData[ -sinV];
								else
									angle = 360 - ArcSinData[ -sinV];

								if (angle >= 0 && angle < 360)
								{
									AverageLength += length;
									tempCount++;

									if (ThreeDOutlineInfo[angle] < length)
									{
										ThreeDOutlineInfo[angle] = length;
									}
								}
							}
						}
					}
				}

				if (tempCount)
				{
					AverageLength /= tempCount;
				}

				for (angle = 0; angle < 360; angle++)
				{
					if (ThreeDOutlineInfo[angle] == -1)
					{
						length = 0;
						tempCount = 0;
						for (tempAngle = angle - 4; tempAngle <= angle + 4; tempAngle++)
						{
							tempAddress = (tempAngle + 360) % 360;

							if (ThreeDOutlineInfo[tempAddress] > -1)
							{
								length += ThreeDOutlineInfo[tempAddress];
								tempCount++;
							}
						}

						if (tempCount)
						{
							ThreeDOutlineInfo[angle] = length / tempCount;
						}
					}
				}

				maxValue = 0;
				for (angle = 0; angle < 180; angle++)
				{
					if (ThreeDOutlineInfo[angle] > -1)
					{
						SymmetryAngle = (angle + 180) % 360;
						if (ThreeDOutlineInfo[SymmetryAngle] > -1)
						{
							length = ThreeDOutlineInfo[angle] + ThreeDOutlineInfo[SymmetryAngle];

							if (maxValue < length)
							{
								maxValue = length;
								SymmetryAxis = angle;
							}
						}

						SymmetryAngle = (angle + 180 - 1) % 360;
						if (ThreeDOutlineInfo[SymmetryAngle] > -1)
						{
							length = ThreeDOutlineInfo[angle] + ThreeDOutlineInfo[SymmetryAngle];

							if (maxValue < length)
							{
								maxValue = length;
								SymmetryAxis = angle;
							}
						}

						SymmetryAngle = (angle + 180 + 1) % 360;
						if (ThreeDOutlineInfo[SymmetryAngle] > -1)
						{
							length = ThreeDOutlineInfo[angle] + ThreeDOutlineInfo[SymmetryAngle];

							if (maxValue < length)
							{
								maxValue = length;
								SymmetryAxis = angle;
							}
						}
					}
				}

				zeroAngle = 0;

				sectionA = min((SymmetryAxis - 90 + 360) % 360, (90 + SymmetryAxis + 360) % 360);
				sectionB = max((SymmetryAxis - 90 + 360) % 360, (90 + SymmetryAxis + 360) % 360);

				shiftAngle = 90 - SymmetryAxis;

				if (tempCount)
				{
					AverageLength /= tempCount;

					tempAngle = tempCount = 0;
					for (y = HalfStartY; y < HalfEndY; y++)
					{
						for (x = HalfStartX; x < HalfEndX; x++)
						{
							tempAddress = HALF_IMAGE_WIDTH * y + x;
							tempHeight = HalfShrinkShapeBinaryImage[tempAddress];
							if (tempHeight)
							{
								dX = x - halfCenterX;
								dY = y - halfCenterY;
								length = dX * dX + dY * dY;
								if (length < 90000)
								{
									length = SqrtData[length]; //sqrtdata는 128이 곱해 진 상태.
									sinV = 1280000 * dX / length;
									if (sinV > 10000)
										sinV = 10000;

									if (dX >= 0 && dY <= 0)
										angle = ArcSinData[sinV];
									else if (dX >= 0 && dY > 0)
										angle = 180 - ArcSinData[sinV];
									else if (dX < 0 && dY > 0)
										angle = 180 + ArcSinData[ -sinV];
									else
										angle = 360 - ArcSinData[ -sinV];

									if (angle >= 0 && angle < 360 && length > AverageLength)
									{
										if (angle >= sectionA && angle < sectionB)
										{
											tempAngle += ((shiftAngle + angle - 180 + 360) % 360) * tempHeight;
										}
										else
										{
											tempAngle += ((shiftAngle + angle + 360) % 360) * tempHeight;
										}

										tempCount += tempHeight;
									}
								}
							}
						}
					}

					if (tempCount)
					{
						tempAngle /= tempCount;
						tempAngle = tempAngle - 90 - shiftAngle;

						zeroAngle = tempAngle * 2; // 720 degree scale
						zeroAngle = (zeroAngle + 720) % 720;
						zeroAngle /= 2;
					}
				}

				TabletSplitLineAngle = zeroAngle;

#ifdef PC_SIM

				for (y = HalfStartY; y < HalfEndY; y++)
				{
					for (x = HalfStartX; x < HalfEndX; x++)
					{
						tempAddress = halfImageWidth * y + x;

						if (HalfShrinkShapeBinaryImage[tempAddress])
						{
							tempValue = min(255, HalfShrinkShapeBinaryImage[tempAddress] * 3);
							ThreeD_Image[MAX_IMAGE_WIDTH * y * 2 + x * 2] = tempValue;
							ThreeD_Image[MAX_IMAGE_WIDTH * y * 2 + x * 2 + 1] = tempValue;
							ThreeD_Image[MAX_IMAGE_WIDTH * (y + 1) * 2 + x * 2] = tempValue;
							ThreeD_Image[MAX_IMAGE_WIDTH * (y + 1) * 2 + x * 2 + 1] = tempValue;
						}
					}
				}
#endif

			}
		}
		else
		{
			blankSW = 1;
		}
	}
	else
	{
		blankSW = 1;
	}

THREED_IMAGE_ERROR:

	if (blankSW)
	{
		DefectSW = 1;

#ifdef TARGET_CPB

		AlignedTabletSW = 0;
		if (TabletCharacter.shape == ETC)
		{
			if (TabletCharacter.length > TabletCharacter.width * 140 / 100)
			{
				AlignedTabletSW = 1;
			}
		}

		if (TabletCharacter.shape == OVAL || TabletCharacter.shape == OBLONG || AlignedTabletSW)
		{
			// for set subcore idle status			
			cacheInvaliDate_ddr3((char *)SubcoreProcessingActiveSW, MAX_PROCESSING_CORE_COUNT * sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);

			// set subcore processing start
			for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
			{
				if (InspectData.CoreProcessingMode[coreIndex] == SPLIT_PROCESSING_MODE_SUB)
				{
					SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * coreIndex] = 2; // error .. 서브 코어들에게 에러 사실을 전달.
				}
			}
			// end set subcore processing start

			cacheWriteBack_ddr3((char *)SubcoreProcessingActiveSW, MAX_PROCESSING_CORE_COUNT * sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
			// subcore에 flag 값을 전달한 상태

			while (1)
			{
				// wait sub core result
				cacheInvaliDate_ddr3((char *)SubcoreProcessingActiveSW, MAX_PROCESSING_CORE_COUNT * sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
				PrcessingCompleteSW = 1;

				for (coreIndex = 0; coreIndex < MAX_PROCESSING_CORE_COUNT; coreIndex++)
				{
					if (InspectData.CoreProcessingMode[coreIndex] == SPLIT_PROCESSING_MODE_SUB)
					{
						if (SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * coreIndex]) // 아직 살아 있는 프로세스가 있는지 체크.
						{
							PrcessingCompleteSW = 0;
							break;
						}
					}
				}

				if (PrcessingCompleteSW) // 모두 종료되었다면 나가기.
					break;
			}
		}
#endif

	}
}

//---------------------------------------------------------------------------

void ThreeDPositionMultiCoreProcessing()
{
	int startX, endX, startY, endY;
	int smallSizeWidth;
	int halfCenterX, halfCenterY;
	int limStX, limEdX, limStY, limEdY;
	int zeroAngle;	

	int AlignedTabletSW;

	AlignedTabletSW = 0;
	if (TabletCharacter.shape == ETC)
	{
		if (TabletCharacter.length > TabletCharacter.width * 140 / 100)
		{
			AlignedTabletSW = 1;
		}
	}

	if (TabletCharacter.shape == OVAL || TabletCharacter.shape == OBLONG || AlignedTabletSW)
	{
#ifdef TARGET_CPB
		do
		{
			cacheInvaliDate_ddr3((char *)&SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER], sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
		}
		while (SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER] == 0); // 스위치가 켜질 때까지 무한 대기.


		if (SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER] == 2) // error
		{
			SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER] = 0; // 에러 발생시에는 즉시 종료.
			cacheWriteBack_ddr3((char *)&SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER], sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
			return;
		}

		cacheInvaliDate_ddr3((char *)&SharedProcessingParamsForRotation, sizeof(TSharedProcessingParamsForRotation));
#endif

		// set processing variable
		startX = SharedProcessingParamsForRotation.ImageStartX[SHARED_MEMORY_VALID_POINTER];
		endX = SharedProcessingParamsForRotation.ImageEndX[SHARED_MEMORY_VALID_POINTER];
		startY = SharedProcessingParamsForRotation.ImageStartY[SHARED_MEMORY_VALID_POINTER];
		endY = SharedProcessingParamsForRotation.ImageEndY[SHARED_MEMORY_VALID_POINTER];
		smallSizeWidth = SharedProcessingParamsForRotation.ImageWidth[SHARED_MEMORY_VALID_POINTER];
		halfCenterX = SharedProcessingParamsForRotation.ImageCenterX[SHARED_MEMORY_VALID_POINTER];
		halfCenterY = SharedProcessingParamsForRotation.ImageCenterY[SHARED_MEMORY_VALID_POINTER];
		limStX = SharedProcessingParamsForRotation.LimitStartX[SHARED_MEMORY_VALID_POINTER];
		limEdX = SharedProcessingParamsForRotation.LimitEndX[SHARED_MEMORY_VALID_POINTER];
		limStY = SharedProcessingParamsForRotation.LimitStartY[SHARED_MEMORY_VALID_POINTER];
		limEdY = SharedProcessingParamsForRotation.LimitEndY[SHARED_MEMORY_VALID_POINTER];
		zeroAngle = SharedProcessingParamsForRotation.ProtoTabletAngle[SHARED_MEMORY_VALID_POINTER];

		// processing start
		CalculateRotataionResultWithMultiCore(startX, endX, startY, endY, smallSizeWidth, halfCenterX, halfCenterY, limStX, limEdX, limStY, limEdY, zeroAngle);

#ifdef TARGET_CPB
		// 정확히 변경된 부분만 덮어 쓸 때는 읽기 안해도 됨.
		//cacheInvaliDate_ddr3((char *)&SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER], sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
#endif

		SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER] = 0;

#ifdef TARGET_CPB

		cacheWriteBack_ddr3((char *)&SubcoreProcessingActiveSW[CACHE_CONTROL_DUMMY_SIZE * CPB_CORE_NUMBER], sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
#endif

	}
}

//---------------------------------------------------------------------------
void CalculateRotataionResultWithMultiCore(int startX, int endX, int startY, int endY, int smallSizeWidth, int halfCenterX, int halfCenterY, int limStX, int limEdX, int limStY, int limEdY, int zeroAngle)
{
	int labelN;
	int x, y;
	int tempAddress;	
	int r;
	int rX, rY, rX2, rY2;
	int shapeMatchingCount;
	int limStY2, limEdY2;
	int tempX, tempY;
	int tempValue, tempValue2;
	int dX, dY;
	int temp_r;
	int tempSinR, tempCosR;

	unsigned char *rotationThreeDImage;
	
	rotationThreeDImage = HalfGradientImage; // 임시용 버퍼.
			
	memset(rotationThreeDImage, 0, (MAX_IMAGE_WIDTH / 2)*(MAX_IMAGE_HEIGHT / 2));
	labelN = 0;

	for (r = -SHARED_PROCESSING_ROTATION_ANGLE; r <= SHARED_PROCESSING_ROTATION_ANGLE; r += 4) // 기준 angle에서 +- 6도 회전(SHARED_PROCESSING_ROTATION_ANGLE : *2 = 12)
	{
#ifdef TARGET_CPB
		cacheInvaliDate_ddr3((char *)SharedJobDistributionForRotation, sizeof(int) * MAX_PROCESSING_CORE_COUNT * CACHE_CONTROL_DUMMY_SIZE * (SHARED_PROCESSING_ROTATION_ANGLE * 2 + 1));
#endif

		if (SharedJobDistributionForRotation[CPB_CORE_NUMBER * CACHE_CONTROL_DUMMY_SIZE][r + SHARED_PROCESSING_ROTATION_ANGLE])
		{
#ifdef TARGET_CPB
			cacheInvaliDate_ddr3((char *)SharedImageBuffer, MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT);
#endif

			labelN++;

			temp_r = ((zeroAngle + r) + 720) % 720;
			tempSinR = SinData[temp_r];
			tempCosR = CosData[temp_r];

			limStY2 = limStY - 40;
			if (limStY2 < startY)
				limStY2 = startY;
			limEdY2 = limEdY + 40;
			if (limEdY2 > endY)
				limEdY2 = endY;

			for (y = limStY2; y < limEdY2; y++)
			{
				for (x = limStX; x < limEdX; x++)
				{
					if (SharedImageBuffer[y * smallSizeWidth + x])
					{
						rX = ((x - halfCenterX) * tempCosR - (y - halfCenterY) * tempSinR) / 1024 + halfCenterX;
						rY = ((x - halfCenterX) * tempSinR + (y - halfCenterY) * tempCosR) / 1024 + halfCenterY;

						if (rX >= 0 && rX < HALF_IMAGE_WIDTH && rY >= 0 && rY < HALF_IMAGE_HEIGHT)
						{
							tempAddress = smallSizeWidth * rY + rX;

							rotationThreeDImage[tempAddress] = labelN;
							rotationThreeDImage[tempAddress - 1] = labelN;
							rotationThreeDImage[tempAddress + 1] = labelN;
							rotationThreeDImage[tempAddress - smallSizeWidth] = labelN;
							rotationThreeDImage[tempAddress + smallSizeWidth] = labelN;
						}
					}
				}
			}

			// 모양을 X축 반전시킨것과 그냥 둔것이 많이 일치할수록 대칭이다.
			// 대칭을 이루는 각도를 구한다.
			shapeMatchingCount = 0;
			for (y = limStY; y < limEdY; y++)
			{
				for (x = limStX; x < halfCenterX; x++)
				{
					if (rotationThreeDImage[smallSizeWidth * y + x] == labelN)
					{
						tempX = halfCenterX + (halfCenterX - x);
						tempY = y;

						tempAddress = smallSizeWidth * tempY + tempX;

						if (rotationThreeDImage[tempAddress] == labelN ||
							rotationThreeDImage[tempAddress - 1] == labelN ||
							rotationThreeDImage[tempAddress + 1] == labelN ||
							rotationThreeDImage[tempAddress - smallSizeWidth] == labelN ||
							rotationThreeDImage[tempAddress + smallSizeWidth] == labelN)
						{
							shapeMatchingCount++;
						}
					}
				}
			}

#ifdef TARGET_CPB
			// 정확히 변경된 부분만 덮어 쓸 때는 읽기 안해도 됨.
			//cacheInvaliDate_ddr3((char *)&SharedProcessingResultForRotation[(r + SHARED_PROCESSING_ROTATION_ANGLE) * CACHE_CONTROL_DUMMY_SIZE], sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
#endif

			SharedProcessingResultForRotation[(r + SHARED_PROCESSING_ROTATION_ANGLE) * CACHE_CONTROL_DUMMY_SIZE] = shapeMatchingCount;

#ifdef TARGET_CPB

			cacheWriteBack_ddr3((char *)&SharedProcessingResultForRotation[(r + SHARED_PROCESSING_ROTATION_ANGLE) * CACHE_CONTROL_DUMMY_SIZE], sizeof(int) * CACHE_CONTROL_DUMMY_SIZE);
#endif

		}
	}
}

//---------------------------------------------------------------------------


